iPhone. How to get the rect of parent view? - iphone

My application creates two views:
topView (CGRect = 0,0, 320,60)
bottomView (CGRect = 0,60, 320,480)
Bottom view creates UITabBarController with UIViewControllers:
ListViewController
etc...
ListViewController has own views that are created in viewDidLoad method:
background = [[UIImageView alloc] initWithFrame: rect ];
So my question is how to get the bottomView rect inside ListViewController?
I want to layout all controller views without intersection with topView.
Thank you.

Might I suggest you read the HIG. Spend a lot of time there as it will answer many design questions that your question shows you don't yet grasp. If you're not able to lay things out with standard controls and positions, you're probably going about it the wrong way.
That being said, your question in the content of your post seems to diverge from the title. If you simply want the parent view's rectangle, use:
CGRect parentRect = [[[self view] superview] frame];
in your view controller.
And when you say ListViewController, is this a view controller you created yourself, one you got from a library somewhere, or do you mean UITableViewController?
I suggest you don't layout your controls with code if you can use Interface Builder instead. That's not always possible, but it's a good practice to use IB when it is.

Related

Best practices for framing a hierarchy of views

From other stack overflow questions, I understand that in your view controller, you can use the viewDidLoad method to initialize subviews and the viewWillLayoutSubviews method to set the frames. This implies that we need to keep a reference of all the views within the view controller instance (as below). This is all fine and great and handles device rotations, etc.
UILabel* myLabel;
- (void)viewDidLoad
{
myLabel = [[UILabel alloc] init];
[myLabel setText:#"Hello"];
}
- (void)viewWillLayoutSubviews
{
[myLabel setFrame:CGRectMake(0, 0, self.view.frame.size.width, 21)];
}
My question is what if you have a complex hierarchy of subviews. For example, what if you have a subview which is a UIView and you add subviews to that UIView (and potentially it even goes deeper). Do you have to keep a reference to every view in this whole view hierarchy so that on viewWillLayoutSubviews, you can modify the frame of each view? This seems like the only way. Are constraints the best way so that you don't have to modify frames as often? Is the best answer to build tons of custom UIViews to make managing this hierarchy more manageable and self-contained within each custom view?
Hopefully this is a clear enough question..thanks in advance.
Anytime you manipulate a view or subview, in a way that could change the layout constraints, you have to call
[view layoutSubviews];
this will remake the constraints with the new property settings. When the viewController is loaded, you would set all properties not dealing with the frame or bounds and then with in the viewWillLayoutSubviews you set the frames of the views this is so all the constraints are made and ensured that they are met.
Any object you put in the storyboard that you want to use, should have a property this will hold a reference to that object. This is a good coding practice, especially if you follow the rules of test driven development.
Now to answer your questions, if you create the complex hierarchy in the storyboard then everything should be fine as long as your constraints are fine, if you make it in code just be sure to call layoutSubviews when ever you call addSubview
Example:
UIView* view1 = [[UIView alloc] initWithFrame:CGRectZero];
UIView* view2 = [[UIView alloc] initWithFrame:CGRectZero];
[view1 addSubview:view2];
[view1 layoutSubviews];
More views does not make the structure better, but if you have 100 subviews... lets be real.. something needs to be categorized in a separate view..
Constraints let you define the frames of views perfectly. You might not notice the differences at first, but if you compare it to Autoresizing Mask then you will see the differences. Also, here is a guide that blatantly shows you the differences.
LayoutConstraints and Autolayout
Also worth considering is using child view controllers if you wish to compartmentalize some of the logic and reuse components.

Best way to create a menu that scrolls up from the bottom?

I'm fairly new to iPhone programming, and I'm making a fairly basic app. Anyway, I just want to know how to go about creating a menu that scrolls up from the bottom (beginning at the top of the tab bar) that displays a few options. I've attached a picture that better helps portray what I mean. I'm assuming I should create some sort of subview and then add some animation to it, but I'd like to get your advice on the best way to start.
Thanks
The simplest solution would be to use a UIActionSheet, unmodified.
If that's not what you're looking for, using a modal view controller is always an option.
If, however, you want something that won't cover the entire screen, and can have a custom look, the basic idea is this:
Create your view with a frame that's just at the bottom of your main view (e.g. at 0,406).
Optionally disable user interaction with the main view
Use UIView animations to move it up
The code would look something like this:
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, kCustomViewHeight)];
[self.view addSubview:customView];
[UIView animateWithDuration:0.2 animations:^{
CGRect f = customView.frame;
f.origin.y -= kCustomViewHeight;
customView.frame = f;
}];
I didn't do it myself, but saw a cool source-code, where it was performed with the helped of UIScrollView (by default positioned "below" the screen), containing UITableView and a button (wich was shown at the bottom of the screen). ScrollView was getting a command to move after the press of this button (in IBAction of it).
Being shorter, try to look at UIScrollView (play with UITableView in it).
I've done something similar, popping up some object from the bottom of the screen by subclassing UIActionSheet and adding my own controls as subviews. I imagine a similar method could be used in your situation.
Create a subclass of UIActionSheet implementing the UITableViewDelegate and UITableViewDataSource protocols. In the - (id)init method of that class, add a UITableView as a subview with self as the delegate and data source.
Then from the main view, call your custom UIActionSheet with showInView:.
Use delegates to call back to the main view to let it know when the user selects an option, then use [myCustomMenu dismissWithClickedButtonIndex:0 animated:YES] to hide the menu.

UISplitViewController with a UIImageView on the Top?

What I want is the normal UISplitViewController, except it's moved down about 100px down so that an image can be at the top.
I tried to put the following in the splitviewcontroller init:
[self.view setFrame:CGRectMake(0, 140, self.view.frame.size.width, self.view.frame.size.height)];
but that didn't do anything.
Can anyone help?
UISplitViewController is built to take all the screen real estate and not really let you do any sort of custom design, even something as trivial as modifying it's frame.
I suggest you take a look at MGSplitViewController if you want to a customizable UISplitViewController.
Also don't forget to modify the frame's height, so part of what your drawing isn't off screen (ex. CGRectMake(0, 140, self.view.frame.size.width, self.view.frame.size.height*-140*)];).
Remy's advice is excellent here. Apple really went out of their way to prevent us from customizing UISplitViewController. MGSplitViewController is a good alternative. The only thing I'd add is that the init method is generally not the best place to adjust your view's frame, as UIKit tends to resize your view controller's view prior to display. A better place to adjust the frame is in viewWillAppear:.

UIViewController frame

I've got the following setup.
A pagingScrollViewController with a UIScrollView as it's view (self.view = scrollView).
In that scrollView I add the view of a rootViewController as subview.
The view of the rootViewController is an UIView on which I add one or the other view (depending on internal logic).
The UIScrollView is initialized with a frame equal to the applicationFrame, so 0, 20, 320 , 460. Which is fine because of the statusbar on top.
The problem comes when adding the rootViewController's view to the scrollview. In the creation process of the rootViewController it's view is setup in -loadView which is still commented out in my case. So the standard appel loadView is processed.
It gives me a view which also has a frame of 0, 20, 320, 460. Which is not as I would like to see it as now the View of the rootViewController is 40 pixels removed from the top of the actual iphone screen.
Now, this is of course easily fixed by manually setting the rootViewControllers view in -loadView or assigning it a frame where the y is set to 0 in -viewDidLoad;
But I cannot imaging that that is the way apple intended this to be done. I'm not using Interface builder, so maybe that's the problem, apple intends me to use IB, but im stubborn on that subject :)
Am I using viewControllers the wrong way? This seemed a nice way to split the logic of the scrollView away from the logic of the other view's.
What would be the correct way to add the view of a second UIViewController to the view of a first UIViewController. In which the first viewController.view receives a frame of 0, 20 , 320, 460. And de second controller.view a frame of 0, 0, 320, 460 (so basically the bounds of the first controller.view)
There's a lot of use of the word controller and view in there, hope the question is clear though.
To answer my own question...
Ravin was right.
After reading up on the loadView method and apple's view controller programming guide I've come to the conclusion that this is the default behavior of the system. If you want anything else, override -loadView and do it yourself. Actually apple states that if you don't use an NIB, you SHOULD override -loadView to create at least a basic simple view.

Sending view to back

When I try to send a view to the back, it hides some of the buttons and labels in my view controller. The view I am sending to the back is a UIImageView. Does anyone have an opinion of what might be the problem?
Here is the code I am using:
UIImage *image = [UIImage imageNamed: #"background.jpg"];
UIImageView *backImage = [[UIImageView alloc] initWithImage: image];
[self.view addSubview: backImage];
[self.view sendSubviewToBack: backImage];
Then, when I am adding controls to self.view, they does not always show
I managed to get it roght by moving my code from init to loadView. I don't understand why that should make a difference, but hey.. it works!
If you are using UIView's sendSubviewToBack: or a similar message, you probably have your buttons inserted in the hierarchy under the UIImageView. When a view moves in the hierarchy, all of its subviews move with it.
To fix this, you need to add your controls as subviews of the same view (possibly the UIWindow) you added the UIImageView to initially.
Without seeing your code, it's very difficult to be more precise.
By not having to add it programmatically and adjust the views, much easier to layer each one in the interface builder. Make sure the image view, if this is set as the background, make sure it is the first to be listed.
Agreed. Not quite sure by what you mean by "send to the back" but here's a guess...
If you are adjusting the layering within your main view, be sure you are not sending a view "to the back" (changing it's layer) that has number of subviews... or else they would all go to the back (their layering would change) at the same time.
If this is totally not what you meant, just let me know, and I'll delete this answer.