I have a separate UIView class that constructs a simple footer bar that contains a UIButton.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:CGRectMake(0, 410, 320, 50)];
if (self) {
int buttonHeight = self.frame.size.height;
int buttonWidth = 70;
int nextBtnPosX =0;
int nextBtnPosY =0;
self.backgroundColor =[UIColor colorWithRed:254.0/255.0 green:193.0/255.0 blue:32.0/255.0 alpha:1.0];
[self sendSubviewToBack:self];
UIButton *nextBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[nextBtn setTitle:#"Next" forState:UIControlStateNormal];
nextBtn.frame = CGRectMake(nextBtnPosX, nextBtnPosY, buttonWidth, buttonHeight);
[nextBtn addTarget:self.superview action:#selector(GoToNextPage) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:nextBtn];
}
return self;
}
I have several ViewControllers that then add this footer view class above to each view as a subview.
UIView *newFooter = [[theFooter alloc] init];
[self.view addSubview:newFooter];
Now the actual UIButton within the footer view needs to have its taget different for each viewController it is added to.
So I though it would be best to add the IBAction to the actual view controller then call this via the footer view.
But this is where I have come into a problem. How do I call the parent Controller to init the IBAction(GoToNextPage) from within the footer subview, from the addTarget?
Also would it be easier to have it all within the footer subview and pass in the target required, if so how else would this be done.
Here is a rough overview on what you should do.
This is how your UIView's header file should look
#protocol myViewControllerDelegate <NSObject>
#optional
- (void)didPushButton:(id)sender;
#end
#interface UIViewController : UITableViewController
{
__unsafe_unretained id <myViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id <myViewControllerDelegate> delegate;
#end
Remember to #synthesize delegate; in your main file.
Finally in your main file, you will have an IBAction that receives the UIButton action.
Let's say that action is named buttonPushed.
Set that action to:
- (IBAction)buttonPushed:(id)sender
{
if (delegate)
[delegate didPushButton:sender];
}
Finally remember, that you need to set the delegate to each viewController you are using this viewController.
UIView *newFooter = [[theFooter alloc] init];
[self.view addSubview:newFooter];
newFooter.delegate = self;
Related
In an OSX-application I have a main class A and a second class B. Both run a window each, at the same time.
In class A there is a button that plays a movie in an AVPlayerView (called playerView) [The movie is loaded into the PlayerView earlier!]:
- (IBAction)runMovieN:(id)sender {
[playerView.player play];
}
This works perfectly fine. The movie is played immediately after clicking the button.
On the other hand, in class B there is a button that calls a method in class A...
- (IBAction)runMovie:(id)sender {
ViewController *runMovieButton = [[ViewController alloc] init];
[runMovieButton runMovie];
}
...which will run this method in class A:
- (void)playPause {
NSLog(#"A");
[playerView.player play];
}
The problem is, that the Log will be printed out perfectly fine, but anything else that is in this method will be ignored, no matter what is in there. The content of the bracket is being ignored completely, except for the Log.
The solution is probably very easy, but I just cannot come up with any that could possibly work.
In your MainViewController.h
#interface MainViewController : UIViewController
-(void)playMedia:(NSURL*)url;
#end
In your MainViewController.m
#interface MainViewController ()
#property(nonatomic, retain) AVPlayerLayer *layer;
#property(nonatomic, retain) AVPlayer *player;
#end
#implementation MainViewController
-(void)playMedia:(NSURL*)url{
self.player = [AVPlayer playerWithURL:url];
self.layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.layer.frame = CGRectMake(0, 0, 200, 200);
[self.view.layer addSublayer: self.layer];
[self.player play];
}
-(IBAction)playButton:(id)sender
{
[self playMedia:[NSURL URLWithString:#"http://content.jwplatform.com/manifests/vM7nH0Kl.m3u8"]];
}
-(IBAction)moveToChild:(id)sender
{
[self.layer.player pause];
[self.layer removeFromSuperlayer];
self.player=nil;
ChildViewController* childView = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
[self presentViewController:childView animated:YES completion:nil];
}
#end
In you ChildViewController.h
#interface ChildViewController : MainViewController
#end
In your ChildViewController.m
-(IBAction)playButton:(id)sender{
[self playMedia:[NSURL URLWithString:#"http://srv6.zoeweb.tv:1935/z330-live/stream/playlist.m3u8"]];
}
Please not if their is no Parent child relation in two classes you can also use delegates to interact between Viewcontrollers
i'm sure it's pretty easy , but i'm spending hours to get it right .
I download this simple menu from github :
https://github.com/Antondomashnev/ADDropDownMenuView
the view controller looks like this :
- (void)addDropDownMenu{
ADDropDownMenuView *dropDownMenuView = [[ADDropDownMenuView alloc] initAtOrigin:CGPointMake(0, 20)
withItemsViews:#[[self dropDownItemWithTitle:NSLocalizedString(#"Item 1", #"")],
[self dropDownItemWithTitle:NSLocalizedString(#"Item 2", #"")],
[self dropDownItemWithTitle:NSLocalizedString(#"Item 3", #"")]]];
dropDownMenuView.delegate = self;
dropDownMenuView.separatorColor = [UIColor blackColor];
[self.view addSubview: dropDownMenuView];}
i'm adding 2 more view controllers to the storyboard.
how can I connect them with Item 2 and Item 3 ? ( so I will see a different View every time i'll click different item ) .
any help will be appreciated...
I've changed demo code to show you solution.
In ViewController.m file add private category with two properties
#interface ViewController ()<ADDropDownMenuDelegate>
#property (nonatomic, strong) NSArray *viewControllers;
#property (nonatomic, strong) ADDropDownMenuView *dropDownMenuView;
#end
Then you need to create set viewControllers array. For example i want to create two instances of ViewController2 class (clean UIViewController template) in viewDidLoad
ViewController2 *vc1 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2Blue"];
[self addChildViewController:vc1];
ViewController2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2Yellow"];
[self addChildViewController:vc2];
self.viewControllers = #[vc1, vc2];
You have to add these view controllers as a child view controller to self. Don't forget about setting storyboardID for your view controllers in storyboard. In this case first view controller has ViewController2Blue storyboardID and second has ViewController2Yellow.
And the last thing to do is implementing ADDropDownMenuDelegate method
- (void)ADDropDownMenu:(ADDropDownMenuView *)view didSelectItem:(ADDropDownMenuItemView *)item
{
NSLog(#"%# selected", item.titleLabel.text);
for(UIViewController *viewController in self.viewControllers){
[viewController.view removeFromSuperview];
}
if([item.titleLabel.text isEqualToString:NSLocalizedString(#"Item 1", #"")]){
[self.view insertSubview:((ViewController2 *)self.viewControllers[0]).view belowSubview:self.dropDownMenuView];
}
else{
[self.view insertSubview:((ViewController2 *)self.viewControllers[1]).view belowSubview:self.dropDownMenuView];
}
}
In this method you remove all UIViewController's views from superview. And then according ADDropDownMenuItemView titleLabel text you add viewController's view to self view.
How do i get the value from different UIViewController in xcode storyBoard?
I end up using prepareForSegue method.
first i create a string in my third view controller.
#property (strong,nonatomic) NSString* stringFromSecondView;
Then I gave the push segue an ID called "getDate" and in my second view class use this code below and remember to import the thirdviewcontroller.h
#import "thirdViewController.h"
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"getDate"]){
NSString *intro = _myDate.text;
thirdViewController *vc = [segue destinationViewController];
vc.stringFromSecondView = intro;
}
}
Now back to my thirdViewController.m
_myLabel.text = stringFromSecondView;
In your second VIew Controller
- (IBAction) btnPressToBringThirdView : (id) sender
{
ThirdViewController* newObject = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
newObject.labelString = #"whatever text you want";
[self.navigationController pushViewController:newObject];
[newObject release];
}
In your third viewcontroller in .h file
#property (nonatomic, retain) NSString* labelString;
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
yourLabel.text = labelString;
}
ViewController *secondview=[[ViewController alloc]init];
secondview.your var here= secondview.your var here+100;//whate you var to change if NSintager
///to save your var
[[NSUserDefaults standardUserDefaults]setInteger:secondview.your var here forKey:#"your key to save"];
I am making an app which uses many Textfields. Most of them are inside static tableViews. I use the split view application template. Every category selected from the left panel presents a storyboard scene inside a second view on the right panel.
I just want to get rid of the keyboard with the "done" button however everything i have tried that would work on a simple view fails to work under these circumstances.
Can you please help me out with this?
p.s. I try to dismiss the keyboard inside the implementation file of the presented storyboard scene. Should i do something inside the Detail Scene of the split view controller?
Here is my Scene's code:
.h
#import <UIKit/UIKit.h>
#interface AfoEsoda : UITableViewController <UITextFieldDelegate>{
}
#property (strong, nonatomic) IBOutlet UITextField *merismataTF;
-(IBAction)hideKeyboard:(id)sender;
#end
.m
#synthesize merismataTF;
- (void)viewDidLoad
{
[super viewDidLoad];
merismataTF.delegate=self ;
}
//---------Hide Keyboard-------------------
//Tried but didn't work
-(IBAction)hideKeyboard:(id)sender {
[merismataTF resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
//Of course i do not use both methods at the same time.
EDIT:
When i set the textfield's delegate to self i get this crash:
Try implementing the textField's delegate, set the delegate to self, and in the delegate's method
- (BOOL)textFieldShouldReturn:(UITextField *)textField
set
[textField resignFirstResponder];
Another way could be going through all of the view's subviews and if it is a text field, resign first responder:
for(int i=0;i<self.view.subviews.count;i++)
{
if([[self.view.subviews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
if([[self.view.subviews objectAtIndex:i] isFirstResponder])
[[self.view.subviews objectAtIndex:i] resignFirstResponder];
}}
OK, I got it. Use this with with the textFieldShouldReturn method.
So here is your answer: You have declared your text field as a property and then use alloc and init it over and over again for each cell. Probably it only works properly for the last row.
Here is an example of how your cellForRow method should look like:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *cellIdentifier = #"My cell identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITextField *newTextField;
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
newTextField = [[UITextField alloc] initWithFrame:CGRectMake:(0,0,25,25)];
newTextField.tag = 1;
newTextField.delegate = self;
[cell.contentView addSubview:newTextField];
}
else
newTextField = (UITextField *)[cell.contentView viewWithTag:1];
And then, if you need the textField's value for a certaing row, simply use:
UITextField *someTextField = (UITextField *)[[tableView cellForRowAtIndexPath:indexPath].contentView viewWithTag:1];
NSLog(#"textField.text = %#", someTextField.text);
I'm trying to build an app where I have a TabBarController with 4 entries.
When I select the first entry, a view with a UITableView shows up.
This TableView is filled with several entries.
What I would like to do is:
When an entry out of that UITableView gets selected, another view should show up; a detailview.
.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
if(self.secondView == nil) {
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondView" bundle:[NSBundle mainBundle]];
self.secondView = secondViewController;
[secondViewController release];
}
// Setup the animation
[self.navigationController pushViewController:self.secondView animated:YES];
}
}
.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface FirstViewController : UIViewController {
SecondViewController *secondView;
NSMutableArray *myData;
}
#property (nonatomic, retain) SecondViewController *secondView;
#property (nonatomic, copy, readwrite) NSMutableArray* myData;
#end
This is what I have so far.
Unfortunately.. the code runs, bit the second view does not show up.
Is your first view controller wrapped in a UINavigationController? When you set up your UITabBarController, you should add UINavigationControllers rather than your UIViewController subclasses, e.g.:
FirstViewController *viewControl1 = [[FirstViewController alloc] init];
UINavigationController *navControl1 = [[UINavigationController alloc] initWithRootViewController:viewControl1];
UITabBarController *tabControl = [[UITabBarController alloc] init];
tabControl.viewControllers = [NSArray arrayWithObjects:navControl1, <etc>, nil];
//release everything except tabControl
Also, based on your code, you don't need to keep your secondViewController as an ivar, since UINavigationController automatically retains its view controllers (and retaining it when you're not displaying it will use up unnecessary memory).