Accessing parent view when adding subview - ios

I have a ViewController that has 2 NSViews in it of different sizes. I'm wanting to add the view of a custom ViewController as a subView to both of these NSViews and have it dynamically size to fill (the 2 parent views). I can accomplish this just fine in the implementation file for the main layout, but its a lot of code. I would like to instead have my custom ViewController do all the work. To do that, I need to know the height and width of the view that I am adding my custom view to. There is a parentViewController property, but it isn't doing anything for me. Is there a way to reference the view that a view is being added to?
In my custom ViewController viewDidLoad method I would like to be able to have
[self.view setFrame:CGRectMake(0, 0,
self.parentViewController.view.frame.size.width,
self.parentViewController.view.frame.size.height)];
but the height and width are both nil here.
I've been digging through documentation for hours and I am still confused. Any help would be much appreciated.

The parentViewController property should be set in the first place. It will be nil if it is not set. You have not specified if it is set correctly. There is a simpler way to do this though, assuming that your view's superview is set correctly. Try this:
[self.view setFrame:self.superview.frame];
or make the rect from the superview's frame if you need to alter something in there.

Related

UIScrollView Frame Always CGRectZero

I have a nib that has the standard UIView and I've also included a UIScrollView as an IBOutlet (yes, it is hooked up), not as a subview of the main UIView, but just out on its own. Autolayout is turned off. The scroll view has several subviews and is larger than the main view. In viewWillAppear:, I set the content size of the UIScrollView to its current frame size, and then set its frame to the size of the main view, and add it as a subview of the main view.
Unfortunately, nothing is showing up. When I NSLog the frame of my UIScrollView, it is coming back as {0, 0, 0, 0} (CGRectZero). I thought this was odd, so I went back and tried logging the frame before I do any changes to it. Still zeroes. Logged it out in viewDidLoad before anything is done to any of my view elements. Still zeroes. (FWIW in my nib, the frame is {0, 0, 320, 896})
I've had this issue with several of my controllers, but it seems to be hit or miss. Sometimes it works, other times I get the empty frame. Typically, recreating everything from scratch seems to fix the issue, but I don't know why, as I'm setting everything up the same both times.
Running Xcode version 6.1 (6A1052d), iOS SDK 8.1 with a deployment target of 7.0
Let me know if there is any other relevant information I can give that might help.
EDIT 1: To address the questions about my UIScrollView being a "subview", here is what my view heirarchy looks like in the document outline:
As you can see, the UIScrollView is a "subview" of the view controller, but is not a subview of the "main" UIView which has the controller's view outlet.
EDIT 2: More images and some code. Here is a better look at how my nib is set up:
I add my scrollView to the main UIView as follows:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
scrollView.contentSize = scrollView.frame.size;
scrollView setFrame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 100); // I slightly modified this because there are other variables that determine its Y position and height
[self.view addSubview:scrollView]
}
But I still don't think any of that code matters- for whatever reason, my UIScrollView is coming back nil. If I have the view created in my nib, the outlet is connected properly, how would the view still be nil? I'm creating my controller via initWithNibName I've tried cleaning the project, and removing the app and reinstalling.
Best guess on an answer, and some comments:
Nibs are simply serialised object trees. You can have as many view as you want as root. The problem (big one!) is that if they are not "connected" to outlets that retain them, at some point you will loose those references.
Since your UIScrollView is not a subview of the main view controller view on the Nib, it's not retained by it (views retain their subviews). So, it's up to you to retain it on your view controller.
My guess is that at the point you are trying to set the frame in the View Controller, the scroll view is already gone. I'm not sure how sure when are you doing it, but it might be after some run loops, so the unretained scroll view is dealloced.
Workarounds:
Instead of a variable for the IBOutlet, use a strong property (#property (strong, nonatomic) IBOutlet UIScrollView *scrollView).
Add the __strong qualifier to the variable.
Add the UIScrollView as a subview within the nib, so when the object tree is deserialised it's already retained by its parent.
Given that you purposefully put the UIScrollView outside of the main view hierarchy, I'm assuming you don't want option 3, so I'll just go with 1.
First, you might want to consider using autolayout. It makes things a lot easier once you make the investment to understand how it works. Check out this Apple doc on using UIScrollview with autolayout.
If that's not an option, the problem is that you're setting up your scrollView at the wrong point in the cycle. The scrollView needs a chance to lay itself out. By the time you hit viewWillAppear, you've missed sub view layout.
So, you could try:
Configure your scrollView in willLayoutSubviews and set its setNeedsLayout property.
Explicitly call layoutIfNeeded on your scrollView in viewWillAppear. The idea is to force another subview layout cycle. But, I'm not 100% sure it would work -- it might be too late at that point.
Note that the size of the main view (self.view) isn't determined until viewDidAppear. It's not always correct in viewWillAppear. So, you have a problem in your setup: you can't really set up your scrollView until you know your view size, but you don't know that until it's too late! You might want to redesign to avoid that dependency.

Using interface builder to layout a scrolling view with images and text

I have a requirement in my app to display a bunch of information that includes both text and images. It will be quite long, so it will need to be scrollable to access all the content.
I know that I can achive this by programmatically adding different UILabels, UIImages etc to a UIScrollView. But this is a proof of concept, so I'm looking for something a little quicker than having to work out all the positioning and code required. The information is static anyway, and does not need to interact with code.
Is there a way to do this using the interface builder (storyboard or xib is fine)?
you definitely can do that if you simply want a quick interface
1.> you might need to know how long is your scroll view, for example in my case, i set it to 1568
2.> Then i drag all the controls that will fit for the first 568 pixel view onto the scroll view and position them.
3.> Then change the Y value for that scroll view to something like - 500, so you can see the rest of the scroll view, and put everything you need there.
4.> After you have all your controls, and remember to set the frame back to 0,0,320,568
5.> last step, in your code, set SCROLLVIEW.contentSize = CGSizeMake(320, 1568);
I would still suggestion don't hard code all those values, but if you are looking for a quick way to do your interface, hope that gives you some ideas.
Just start a new project with a single view, it will come with a xib or storyboard for its single ViewController.
Create a UIView by dragging it into the workspace and place as many Labels, Images and UI Elements as you want.
Open the xib / storyboard and drag a UIScrollView in as your root VC's root view. Drag the view containing your layout into the scrollview, making it the scrollviews only subview.
Done (almost)!
If you launch your app at this point, you'll notice you can't scroll. That is because the scrollview is "too stupid" to adjust the size of its contentSize property on its own.
You'll need some code here, but it is only a tiny snippet and you won't need to touch it again:
Create a new Category on UIScrollView.
In your category's implementation, do:
#implementation UIScrollView (MyHandyCategory)
-(void)awakeFromNib {
NSArray *subViews = [self subviews];
UIView *contentView = [subViews objectAtIndex:0];
[self setContentSize:contentView.frame.size];
}
#end
Done (for real this time)! This will check the size of the view your scrollview contains and ajust the contentSize after it has been initialized. You can change the size of your content view as you like, no need to play around with hardcoded values or even Interface Builder values!
If it’s just proof of concept I’d have a WebView and a local HTML page you load. Easy-peasy.
I would suggest UICollectionView. It's fairly straightforward. There's a good tutorial here:
http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12

Setting the frame of an UIView does not work

I have a problem with the frame-property in iOS 7.
I wanna resize some UIViews in the viewDidLoad-method of my UIViewController, but if I do it like int screenHeight = [[UIScreen mainScreen] bounds].size.height;
[self.leftSideTableView setFrame: CGRectMake(0, 0, 320, screenHeight)];
the height is set as I want it till the end of the method, but in every other method it is as is has been before!
What's wrong with it or is it just a bug of the compiler or anything else?
One has to put view resizing into -viewDidLayoutSubviews:! (documentation)
Placing view frame changes into -viewWillAppear: or -viewDidLoad: will not work, because the views are not laying out yet!
Check if you are using autolayout in your xib file. If you don't want to use autolayout, uncheck it in your xib file.
Change your self.leftSideTableView frame in -viewWillAppear:.
Check to make sure that auto layout isn't activated in your storyboard file.
To turn it off, look at the inspector in interface builder. Click the icon that looks like a page all the way on the left. In the section "Interface Builder Document" uncheck "Use Auto Layout."
I find it's best to an entire view controller in IB with auto layout, or completely in code. Mixing the two can lead to weird behavior that is hard to debug.
There are several reasons why this might be happening. First of all, you need to make sure that your tableview isn't nil. If you're creating it programmatically, you need to be sure that you're calling alloc/init somewhere before you attempt to set the frame. If self.leftSideTableView is an IBOutlet, this can be caused by forgetting to actually link the outlet to the interface object.
Then, second and less likely, you are creating the table view programmatically and initializing it properly, but you forgot to add it as a subview of one of your on screen views.

UIScrollView not scrolling at all

I have a composite structure of view controllers - parent view controller's view has a hole in it where I embed other view of another view controller.
I use addChildViewController and then add that child view to my view.
Now the tricky part - that view has UIScrollView and it refuses to scroll. I have made that UIScrollView in Xib, by embedding two other views in it.
I have checked frame and contentSize of that scrollView, and everything is normal, content size is big, frame is actual.
In viewDidLoad I use this:
self.scrollView.contentSize = CGSizeMake(3000, 3000);
I have tried setting delegate, userInteractionEnabled, scrollingEnabled but none of these helped. I have tried setting all superviews UserInteractionEnabled and such, but it didn't help too.
I have a feeling that it is a bug with Xcode, and I might just make scrollview in code, but this pisses me off, since I have huge hierarchy of labels and it will be hard to make them in code.
I use ios5 and no autolayout.
I tried changing background color to green and I can see the scrollview on screen, it is on correct place.
If you are using paging then use
self.scrollV.contentSize = CGSizeMake(self.scrollV.frame.size.width *kNumberOfPages, 220);
self.scrollV.showsHorizontalScrollIndicator = NO;
self.scrollV.showsVerticalScrollIndicator = NO;
self.scrollV.scrollsToTop = NO;
self.scrollV.delegate = self;
Here you can use number of pages to show.But before this please set delegate UIScrollViewDelegate of UIScroll view to that class. Please also check autolayout in your view too.
Hope this helps.

iOS: How can I figure out the size of the view in the super view's layout?

When I use self.view.frame.size.height, it gets the height of the child nib, rather than the height of how the view is going to fit into the overall layout. I get the same value using self.view.bounds.size.height and super.view.bounds.size.height.
Any help would be appreciated.
Ask at the right time. Not until the view is ready to appear has iOS figured out what size it will actually be. Move your code that depends upon the view being the right size to viewWillAppear instead of viewDidLoad or an init method.
In Xcode 4 you would select your view controller that contains the UIScrollView and set the 'Simulated Metrics' in the IB Attributes Inspector as follows:
This ensures that your UIScrollView will be set to the correct size to fill the available space at design time. It looks like you are using an older version of Xcode/IB and I can't remember exactly where these settings used to be but they're in there somewhere.
With the layout designed to accommodate the space taken up by the tab bar you should be able to query the size of the UIScrollView at any time and get the correct values.

Resources