So I have a view controller called MainViewController with a button which when I press this code is called:
NewViewController *newViewController;
newViewController = [[NewViewController alloc] initWithNibName:#"NewView" bundle:nil];
[self.navigationController.view addSubview:newViewController.view];
[newViewController release];
This brings in the new view which works great. However, how can I remove this view from a button within it? In an application I wrote a while ago I simply created a method in MainViewController called RemoveView and within the XIB file for NewViewController I selected FirstResponder and then RemoveView for the button. This works but I can not replicate it in my new project and don't really understand how it works anyway!
It's not the remove view code I'm looking for, more the way of getting the method to call from another class.
If anyone could help me that would be great! :)
Thanks
Drawing the line in Interface Builder does the same thing as calling
[theButton addTarget:theController action:#selector(theAction) forControlEvents:UIControlEventTouchUpInside];
theAction needs to be a method that is defined with a type of IBAction.
For your situation, in your NewViewController.h, declare
- (IBAction)removeView;
Then in NewViewController.m:
- (void)removeView
{
[self.view removeFromSuperview];
}
In your newView.xib file, you should be able to drag a line from the UIButton that you've drawn to your File's Owner, and select the removeView action.
Related
I have two xib files. I start with "ViewController.xib" and when the user clicks a button it loads a different xib file named "GamePage.xib".
The code of the button is:
-(IBAction)startButtonClicked{
UIViewController *gamePage = [[UIViewController alloc] initWithNibName:#"GamePage" bundle:nil];
[self presentViewController:gamePage animated:NO completion:nil];
}
When the button is clicked, the second xib is shown on screen, but its "viewDidLoad" method don't run…
Why is that?
UIViewController *gamePage = [[UIViewController alloc] initWithNibName:#"GamePage" bundle:nil];
This does not seem correct.
viewDidLoad is probably running but it is viewDidLoad of Apple's UIViewController. You should use your class instead of UIViewController when you initialize it. In general you should use the class which viewDidLoad you need called.
Your XIB must have its Owner. You need to create a class derived from UIViewController and then you need to make that class owner of your XIB.
Just follow these steps:
Open you project
Select the Project Name in the Left Navigation Panel
Right Click and select New File
Select Objective C Type Class
When you click on it, it will ask you to give it a name
Suppose you gave GameViewController
Check the "With XIB for Interface"
and then add the files
Now in your Navigation Panel you will see three classes
GameViewController.h
GameViewController.m
GameViewController.xib
Create your interfaces in your xib.
And now if you have to move to this class and show its view, write the following code:
-(IBAction)startButtonClicked{
GameViewController *gamePage = [[GameViewController alloc] initWithNibName:#"GameViewController" bundle:nil];
[[self navigationController] pushVIewController:gamePage animated:YES];
[gamePage release]; //If not used ARC
}
Here's my code
-(IBAction)showMenu:(id)sender
{
Demo *mainMenuTableView = [[Demo alloc] init];
UIPopoverController *pop = [[UIPopoverController alloc]initWithContentViewController:mainMenuTableView];
[pop setDelegate:self];
}
Demo is my xib that contains a tableview controller stuff. This "Demo" works just fine as a fullscreen view.
I'm trying to create a popover with this view, but I've tried what I think is every other solutions on stackoverflow, but I still cannot determine how to create and call the popover...
I'm sure I'm like a line of code or two away... I hope.
Any help would be appreciated!
Thx!
After you create the popover controller, you have to tell it to present the popover. You can use either presentPopoverFromRect:inView:permittedArrowDirections:animated: or presentPopoverFromBarButtonItem:permittedArrowDirections:animated:. For example, I assume that you have connected showMenu: as the action of a UIButton. So you can add this at the end of showMenu::
UIButton *button = (UIButton *)sender;
[pop presentPopoverFromRect:button.bounds
inView:button
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
You also need to put a reference to the popover controller in an instance variable or property. Otherwise the popover controller will be deallocated when showMenu: returns, which will cause a crash. Thanks to Floydian for pointing this out.
You need to retain the "pop" variable! Just set a UIPopoverController "POV" as your property and use below code in your IBAction.
self.POV = [[UIPopoverController alloc]initWithContentViewController:mainMenuTableView];
[self.POV presentPopoverFromRect:button.bounds
inView:button
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
Bit confused with this one so bear with me...
I have a Navigation-based project which is working fine. I'm trying to create my first custom UIView to make a couple of buttons which I will use in multiple places. One of the buttons needs to push a viewcontroller into the navigation when it's clicked but I'm not sure how to do this.
When I had the button set up within a view controller I was using:
LocationViewController *controller = [[LocationViewController alloc] initWithNibName:#"LocationViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
but the self.navigation controller won't work now, will it? How do I access the navigation controller of the viewcontroller that this uiview will be added to?
Hope at least some of that makes sense, as I said it's my first go at subclassing the uiview and adding it to multiple pages so I'm a bit lost.
EDIT TO ADD - I have the button click events inside the custom UIView, so that is where I'm trying to change the viewcontroller from. Should I instead wire up the events in whichever viewcontroller I add the view to?
Usually your appDelegate has a UINavigationController property. You can access it in your custom view like this:
UINavigationController *navController = (MyAppDelegate *)[[[UIApplication sharedApplication]
delegate] navigationController];
But more effective way is to make delegate method for your custom view and handle button action in your viewController.
MyCustomView.h
#protocol MyCustomViewDelegate
#interface MyCustomView : UIView {
id<MyCustomViewDelegate> cvDelegate; }
#property(nonatomic, assign) id<MyCustomViewDelegate> cvDelegate;
#protocol MyCustomViewDelegate #optional
-(void)didClickInCustomView:(MyCustomViewDelegate*)view withData:(NSObject*)data;
#end
MyCustomView.m
- (void)myButtonClick:(id)sender
{
[self.cvDelegate didClickInCustomView:self withData:someData];
}
So now you can handle this event in any place where is your custom
view.
Add the button from the interface builder or from the view controller's viewDidLoad using code:
CGRect frame = CGRectMake(0, 0, 24, 24);
UIButton *button = [[UIButton alloc] initWithFrame:frame];
[button addTarget:self action:#selector(handleMyButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
Then implement -(void)handleMyButton:(id)sender {}; in your view controller. Or you could instead write -(IBAction)handleMyButton:(id)sender {}; and link method and button using the interface builder.
Then inside the method just paste the block of code you posted above. If you started with the Xcode navigation controller template project it should work.
I think it's cleaner to hide the designated initializer initWithNibName: because it is an implementation detail.
When you say you are subclassing the UIView I don't know exactly what you mean. If you want to add another view controller with a custom view just use the UIViewController template and customize the XIB file, no need to subclass an UIView unless you are really modifying its behaviour, which I guess you are not. The view is a view, and the controller stuff like handling buttons should be in the controller.
The actual controller need to be in the navigation controller stack to be able to push another controller.
Or you can make a new navigation controller instance and push your LocationViewController.
I have a simple app that have 3 views, HomeView, MenuView and GameView.
In the HomeView I have 2 buttons (Menu and Start Game). When the menu button is clicked, I open the MenuView using the following code:
- (IBAction)displayMenu:(id)sender{
MenuView *mv = [[MenuView alloc] init];
[self.view addSubView:[mv view];
[mv release];
}
In the MenuView, I have a button that will allow the user to return to the HomeView. When this button is clicked, I use the following code to return to the HomeView
- (IBAction)returnToHome:(id)sender{
HomeView* hv = [[HomeView alloc] init];
[self.view addSubView:[hv view];
[hv release];
}
The above code is working but is this the correct way of doing it? I was under the impression that when I call the addSubView, the view will be retain so If keep going back and forth between HomeView and MenuView, will i have multiple instance of HomeView and MenuView retained since I keep calling addSubView from each of the view?
Thank you.
You could use the UINavigationController, which will allow you to push UIViewControllers on to the stack.
Using the UINavigationController you will get an nice naviagtionbar in at the top of you screen and the back button.
You can find a nice example here:http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
I found this way the most useful and convenient. When calling the new view use this:
HomeView* hv = [[HomeView alloc] init];
(here you can add a uninavigation controller)
[self presentModalViewController:hv animated:YES];
Then to dismiss this view and go back use this:
[self dismissModalViewControllerAnimated:YES];
#atbebtg:
There is a way to do that, infact there are several, since there not really is a "right way" to do it.
For me this works well:
[[self navigationController] setNavigationBarHidden:YES animated:NO];
This will hide the Navigation Bar, so the user can't go back to the last screen.
The other thing you could do is to create your own subclass of UIViewController and not support the button event, like this:
- (IBAction)done:(id)sender
{
//inform the user, that going back is not possible, for example with UIAlertView
//[self.delegate infoViewDidFinish:self];
}
However, this solution seems a bit odd, because the user expects a existing button to work.
Still, this would work.
Others have given answers that present modal view controllers or build a navigation stack. In most cases I would use one of these approaches. Yet, the simplest way to fix the code in the question is to just remove the menu view from the super view. Something like this:
- (IBAction)returnToHome:(id)sender{
[self.view removeFromSuperview];
}
I have a ViewController that responds to some touchEvents (touchesBegan, touchesMoved, etc...).
I've found that when I show this controller using presentModalViewController: it works just fine, but I'm trying to add it's View as a subview of another ParentViewController like so:
- (void)viewDidLoad
{
[super viewDidLoad];
//Add SubController
controller = [[SubViewController alloc] initWithNibName:#"SubViewController" bundle:nil];
controller.view.frame = CGRectMake(0, 30, 300, 130);
[view addSubview:controller.view];
[controller release];
}
When I do this, it gets added the parent view but it no longer responds to touch events. Is there a way to fix this?
Also, is there a better way to go about this? I know I probably could have used a View subclass for the child view, but it's supposed to use a Nib and I wasn't sure how to handle that without using a ViewController.
You're correct you should use a UIView subclass.
The easiest way to load it from a nib is to include the subview in your nib.
Just drop a UIView into the view connected to the original view controller.
Then with the view inside selected go to the identity inspector. It's the one that looks like a little ID card.
The very first field is called Custom Class.
Type the name of your UIView subclass here.
If you need a reference to this just create an IBOutlet in your original view controller and hook it up. That way you can set hidden = YES until you need it.
In your UIView subclass you might want to override
- (void)awakeFromNib
This will get called when the nib first unpacks.
for setting up any gesture recognizers, etc.
To load a nib directly into a view :
// Get the views created inside this xib
NSArray *views = [NSBundle mainBundle] loadNibNamed:#"myViewNib" owner:nil];
// There's probably only one in there, lets get it
UIView *myView = [views objectAtIndex:0];
// Do stuff . . .
[[self view] addSubview:myView];
You could try to call becomeFirstResponder in your subview and see whether it receives touchesBegan... It is probably so, but it will also possibly make the superview not receive touchesBegan if you require it...