How to get a UIViewController from a UIView via code [duplicate] - iphone

This question already has answers here:
Get to UIViewController from UIView?
(29 answers)
Closed 8 years ago.
There is a way to get a view controller reference from a UIView object? I need something like this:
MyParentViewController *myParentViewController = [self.view.superview controller];

You can use the -nextResponder method to do it. According to http://developer.apple.com/library/ios/documentation/uikit/reference/UIResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/UIResponder/nextResponder , "UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t)"

UIView does not have reference to UIViewController by default.You can add it to your UIView subclass and set it when you create UIView in UIViewController.
If you are looking for parent of the viewcontroller, each UIViewController has property parentViewController, but if you want to access this from UIView you need to first get to your UIViewController.
You can see example how to create reference to your UIViewController in your subclass of UIView and how/where to set it up in View Controller Programming guide for iPhone, see section Creating the View Programmatically in Defining a Custom View Controller Class, here is the example, for more details see the linked Metronome example.
- (void)loadView {
self.wantsFullScreenLayout = YES;
MetronomeView *view = [[MetronomeView alloc]
initWithFrame:[UIScreen mainScreen].applicationFrame];
view.metronomeViewController = self;
self.view = view;
self.metronomeView = view;
[view release];
}
In header:
#interface MetronomeView : UIView {
MetronomeViewController *metronomeViewController;
...

You can use
[(MyParentViewController *)[[self.view superview] nextResponder] doSomething];

You shouldn't save the reference to the view controller as it may change dynamically.
Traverse the responder chain every time you need it.

You can use the following:
UIViewController* yourViewController =
(UIViewController*)[(YourAppDelegate*)
[[UIApplication sharedApplication] delegate] viewController];

Related

how to load custom view with xib on a xib or storyboard

I just want to load a custom view (with xib) on a viewcontoller's xib or stroy board.What is the best practice to do the same.
I have used awakeAfterUsingCoder function code below.
(id) awakeAfterUsingCoder:(NSCoder*)aDecoder
{
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder)
{
CustomView* theRealThing = (id) [CustomView view];
theRealThing.frame = self.frame;
theRealThing.autoresizingMask = self.autoresizingMask;
return theRealThing;
}
return self;
}
but after using this function my awakeFromNib started calling multiple time.
Please sugegst.
The correct answer currently linked to is overly complicated and buggy, as you have found out. There is a much more standard and better way to do this:
Create an empty XIB
Add a UIView to your XIB so that it is the only top-level object (aside from the proxies First Responder and File's Owner)
Change the class of your new UIView to CustomView
Instantiate the XIB and retrieve your CustomView instance like so:
CustomView *view = [[UINib nibWithNibName:#"CustomView" bundle:nil] instantiateWithOwner:self options:nil][0];
Add it to your view hierarchy in your view controller's viewDidLoad method:
[self.view addSubview:view];
Be sure to override -initWithCoder: in your CustomView subclass in case you need to do any custom initialization. I know this is a lot, so please let me know of any if these steps confuse you or if you get stuck.

iphone development: how to put a UIView over UITableView [duplicate]

This question already has answers here:
How to add a UIView above the current UITableViewController
(21 answers)
Closed 8 years ago.
In my app I use storyboard. One of my elements in the storyboard is a UITableViewController. So it has a tableview inside of it.
My question is how can I put a UIView over this tableview. It is gonna be hidden and I want to make it visible when a tableviewcell in the tableview is pressed. Is that possible? How can I do that?
The best solution is use normal view controller (UIViewController) in StoryBoard. Your controller will need to implement two protocols (UITableViewDataSource and UITableViewDelegate) and you will need add UITablewView in the view controller's view.
In this case in interface builder you will be able to put any view in the view controller's view (can put it above table view).
Use tableHeaderView property.
Returns accessory view that is displayed above the table.
#property(nonatomic, retain) UIView *tableHeaderView
The table header view is different from a section header.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html
Lets assume your view to be hidden/shown on top of table view is topView, declared as a global variable.
Declare topView in .h as
UIView *topView;
Now Lets assume that you have the UITableViewController object as tableViewController then, initialize the topView in viewDidLoad of tableViewController class
-(void)viewDidLoad
{
topView=[[UIView alloc] initWithFrame:yourNeededFrameSize];
[self.tableView addSubview:topView];//tableView is a property for UITableViewController inherited class
topView.hidden=YES;//Hide it initially for the first time.
}
assuming that you have the UITableViewDelegate methods implemented here is what you will do in didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(topView.isHidden==YES)
{
topView.hidden=NO;
}
else
{
topView.hidden=NO;
}
}
hope it helps.
you can also get view into front.
[view bringsubviewtofront];
I had a similar problem where I wanted to add a loading indicator on top of my UITableViewController. To solve this, I added my UIView as a subview of the window. That solved the problem. This is how I did it.
-(void)viewDidLoad{
[super viewDidLoad];
//get the app delegate
XYAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//define the position of the rect based on the screen bounds
CGRect loadingViewRect = CGRectMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2, 50, 50);
//create the custom view. The custom view is a property of the VIewController
self.loadingView = [[XYLoadingView alloc] initWithFrame:loadingViewRect];
//use the delegate's window object to add the custom view on top of the view controller
[delegate.window addSubview: loadingView];
}

Draw SubView in Storyboard

I want to present a modalView (it can be a viewController) that I draw in Storyboard. I don't want to have to make the whole thing programmatically. Is there a way to do this without it being a full screen view?
I guess another way to ask the question is: how do I [self.view addSubView:mySubView] where mySubView is drawn in InterFaceBuilder/Storyboard?
To do this properly, you should look at View Controller containment in the docs. Basically you would addChildViewController after instantiating the viewController from your storyboard and then add the viewController's view to your current view hierarchy.
To just get it working however, the following will get you going:
UIViewController *childViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"<identifier you set in Interface Builder>"];
[self.view addSubView:childViewController.view];
Note that one of the reasons to do it 'properly' will be to ensure that autorotation and presentation callbacks are sent to the sub view controller.
Override the initWithCoder method in the object-c class.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0]];
}
return self;
}

How to use AppDelegate alternateView in Kobold2D to replace rootViewController

I want to create a Kobold2D app with a container view that will hold both the cocos2d CCDirector view and my own UIViews. I can see from documentation that this can be done using the alternateView method in the AppDelegate but I can't see how to use this method and what exactly it should return. Could you provide me with an example?
It should simply return a UIView. The "Cocos2D with UIKit Views" template project uses the alternateView method to create exactly this kind of container view:
#implementation AppDelegate
-(id) alternateView
{
// we want to be a dummy view the self.view to which we add the glView plus all other UIKit views
KKAppDelegate* appDelegate = (KKAppDelegate*)[UIApplication sharedApplication].delegate;
// add a dummy UIView to the view controller, which in turn will have the glView and later other UIKit views added to it
CGRect bounds = [appDelegate.window bounds];
UIView* dummyView = [[UIView alloc] initWithFrame:bounds];
[dummyView addSubview:[CCDirector sharedDirector].view];
return dummyView;
}
#end
This code goes in your project's AppDelegate.m

iOS4 - custom uiview accessing UINavigation stack

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.