get height of a content view subview in a scroll view - ios

I'm trying to understand how scroll views works with autolayout.
I have understood that there are 2 ways of getting it to work, the pure version or the mixed version. I'm trying the mixed version, following the recepi on this page: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
I have a scroll view with a contentView as the first subview. According to the apple recepi i need to do this:
[scrollView setContentSize:CGMakeSize(contentWidth,contentHeight)];
I have set my contentView to be 600 pt high, but when i run the app it just logs the screen size and not the actual size of the contentView.
NSLog(#"%#", NSStringFromCGSize(self.scrollViewContent.bounds.size));
This logs {320, 568}
What am i doing wrong?

According to your comments, the view hierarchy as below. Concept behind this, even if you change content size of your scroll view, it won't change size of all subviews.
---ScrollView
-----scrollViewContent
------OtherViews
If you want to change size of content view according to content size, just change size too for content view frame.
CGRect newFrame = self.scrollViewContent.frame;
frame.size = scrollView.contentSize;
self.scrollViewContent.frame = newFrame;

Related

Resize view in UIScrollView

I am so confused about UIScrollView.
I'm working with a view contains many other views. And that view placed in a UIScrollView.
How can I change height of this view?
I've tried so many ways but they didn't work. I tried to change frame by CGRect but view's child went wrong.
First of all you should be using constraints using auto layout.If all the constraints are justified then the there will be no warning.At that moment the scrollview will fit all the views under its contents view and mange the content size of it by itself.
If you want to increase any view in the scrollview to increase in height you may increase the height constraint and the scrollview will manage the constentsize by itself.

Why UIView is wider than Screen

I've created a view controller using interface builder, while size classes is on.
the view has leading and trailing constraints to it's super view which is the view controller's view. something like this.
|-(14)-(view)-(14)-|
When i'm running the app it looks great, the view has those 14pt insets on both sides, though when I print it's width I get 576 which is wider than the screen width. In interface builder the view's frame width is set to 576 (as the canvas size when size classes is on) but at run time the constraints should override this I guess.
How come the view appears right, but it's frame shows a bigger width ??
When did you print the width ?. I guess in ViewDidLoad. Because you use Interface Builder and enable size classes, so by default, the width and height are 600x600. At the time view did load, the size still refer the size from Interface builder until view did appear, it will be automatically scaled according to the screen size. That why your UIView is wider than the screen.
Here is what I printed out from a view controller built using Interface builder and enable size classes. Run on iPhone 6S plus
[Size] at view did load {{0, 0}, {600, 600}}
[Size] at view did appear {{0, 64}, {414, 623}}
You can use the below methods to update your view:
// Allows you to perform layout before the drawing cycle happens. layoutIfNeeded forces layout early
[view setNeedsLayout];
[view layoutIfNeeded];

Can't get UIScrollView to work

This is a storyboard app. I added a UIScrollView on top of the UIView that is there in the view controller by default. Then I added some UI elements on to the scroll view. After designing the viewable part of the Scroll view, using its handles I stretched it vertically and pushed it up a bit so that that part is visible for me to design the rest of the screen. After I was done I positioned the scroll view back to fit the view. Please note that I did not resize the scroll view to match the size of the view from the IB.
Then I added all 4 constraints to the scroll view (Leading and Trailing space to superview, Top and Bottom space to superview). Then I selected the UIView, opened up the size inspector and changed the Bottom Space to superview's value to 0. That automatically resized the UIScrollView to fit inside the view controller.
Then I added the following lines of code inside the viewDidLoad method.
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.frame.size.height);
self.scrollView.frame = self.view.frame;
But this does not work. The UIScrollView won't scroll. Yes, the scrolling is enabled.
Can anyone please tell me what I might be missing here?
Thank you.
EDIT:
I found an old project of mine here. It utilize the way I just explained above and it works! No idea why it doesn't anymore.
I also added a demo project here with the issue.
If I understood your code correctly (a screenshot of the view would help) you set the scrollviews frame to be full size of the view and set then contentSize to the view's size. A scrollview scrolls only if the contentSize is larger than its size.
This might not be the complete answer to your question, but it will help you and others for sure.
To design the views that are bigger in size than the size of the UIScrollView, the best way to have the UIView as a child view to UIScrollView and put all the content on the UIView and finally place the UIView as subview of the UISCrollView. AT last you can set the size of the UIView as the content size of the UISCrollView.
Cheers. :)

Need to change UIScrollView contentSize when portrait xib is adjusted to landscape

I've got a UIViewController with an iPad xib in portrait orientation. When my iPad is in landscape orientation and I put that view controller into my UISplitViewController's detail pane, it gets automatically resized to fit which is great.
However, when I'm configuring my views in -viewDidLoad, the final size of the views is not yet in landscape orientation/size.
The -didRotateFromInterfaceOrientation: method and the other methods associated with it do not get called when the UIViewController is loaded already in landscape, so when and where am I able to properly set the contentSize of the scroll view and it's contents?
I only want my scroll view to scroll vertically, so I want to make sure that my contentView inside the scrollView is re-fit to the width of the view controller in whatever orientation it is in.
No matter what .frame or .bounds I check, whether it's on my view, my scroll view, or even the detail view controller of my SplitViewController show me what my ACTUAL size is. When in landscape using a UISplitViewController, the left hand side is 320px wide which means the right hand side shouldn't be more than 704px wide, but whenever I check the frames and the bounds of my view and my scrollview, they report as 768px wide which is not correct.
My scrollview is CLEARLY only 704px wide because I can see the scroll indicators correctly.
What am I missing?
Here is my code in -viewDidLoad...
CGSize textSize = [self.purchase.textDescription sizeWithFont:self.labelTextDescription.font constrainedToSize:allowedSize lineBreakMode:UILineBreakModeWordWrap];
CGRect textFrame = self.labelTextDescription.frame;
textFrame.size.height = textSize.height;
self.labelTextDescription.frame = textFrame;
CGRect contentFrame = self.contentView.frame;
contentFrame.size.height += textSize.height;
if (contentFrame.size.width > self.scrollView.frame.size.width) {
contentFrame.size.width = self.scrollView.frame.size.width;
}
self.contentView.frame = contentFrame;
[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.frame.size;
The proper time to lay out your views and set your scroll view's contentSize is during the layout phase of the run loop. During this phase, UIKit sends the layoutSubviews message to any view that has been marked as needing layout and is in a window. A view is automatically marked as needing layout when various things happen, including when it is first added to a window hierarchy, when it is given a new subview, and when its size changes. You can also manually mark a view as needing layout by sending it the setNeedsLayout message.
By the time a view receives the layoutSubviews message, UIKit has already sent layoutSubviews to any of the view's ancestors (its superview and up) that needed it, and it has already had its frame adjusted based on its autoresizing mask or autolayout constraints, and its own subviews' frames have already been adjusted based on their autoresizing masks or autolayout constraints.
If self.view is already a custom subclass of UIView, the best approach is simply to override layoutSubviews in that class. Put your layout code there, and set the scroll view's contentSize there.
If you're not using a custom subclass, and you don't want to create one, then you can do the layout in your view controller's viewWillLayoutSubviews or viewDidLayoutSubviews method, if you're deployment target is iOS 5.0 or later. You can probably guess when these messages are sent. :)
During autorotation, all of these messages (layoutSubviews, viewWillLayoutSubviews, and viewDidLayoutSubviews) are sent inside the autorotation's animation block, so if you do your layout in one of these methods, you also get the benefit that the changes to your layout will be animated during the autorotation animation.
First of all, if you don't want to get the view resized when rotating check the autoresize mask. If you built the view in the interface builder then check that it's not changing it's size when the superview does:
You can check the current interface orientation of your UIViewController with self.interfaceOrientation. This might help you if you want to set up you view manually.
Furthermore, if you need to adjust the sizes manually then set the desired frames to your views before (or after) the rotation is performed:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
I would recommend query the status bar orientation to get the current rotation in viewDidLoad I would recommend not relying on auto-resizing for scroll views as it tends to get tricky. Check the status bar the resize proportionally based on that.
[UIApplication sharedApplication].statusBarOrientation

UIScrollView Interaction Area does not update with frame/contentSize

I have a UIScrollView which starts with a portrait aspect and which I subsequently (after device rotation) move to another frame which is a landscape aspect.
Accordingly the content view (A UIView inside the UIScrollView) is updated and I set the contentSize of the UIScrollview.
The issue is - after rotation - the UIScrollView has a new frame, new content and new contentSize but the area inside which the user can swipe still behaves as if it was the original frame/content.
Image 1 shows the original aspect / Image 2 shows the new aspect with the odd area available to the user for their swipe gestures.
As you might expect I've fiddled with quite a few of the settings in the scroll view such as the bounds etc but nothing to date has 'fixed' this behaviour.
Any insights into why this behaviour is happening and/or how to set the user interaction area to the frame/bounds of the scroll view would be greatly appreciated.
EDIT2:
There are 3 views in this hierarchy
Lanscape
mainView Frame {0,0,1024,748}
resultsView Frame {633,90,361,677}
scrollView Frame {20,60,340,595}
Portrait
mainView Frame {0,0,532,1240} <--- Whoa Horsy - I expected .... {0,0,768,1004}
resultsView Frame {0,659,768,345}
scrollView Frame {0,70,768,280}
At this point I went into every nib in the project and made sure that autoresizes was turned off and I also tagged every view with a different number so that at the time I was checking the frames I could be sure certain definite positive of what I was looking at.
The top level view in the stack WAS autoresizing and now with that turned off I am getting this for the portrait result..
mainView Frame {0,0,768,1004} ..... YES! WIN.....
resultsView Frame {0,659,768,345}
scrollView Frame {0,70,768,280}
EDIT1:
Setting the resizing mask as comments below reduces the visible size of the scrollview to match the interaction area - so making it seem that the scrollview really does think it's frame is that size only (768 made to look like 468 or so). Increasing the width of the frame does indeed increase the size of the scroll view but there are only 768 pixels for the full width so why should a frame thats 768 wide look like 468 and a frame of 686 look like 568?!
It sounds like you've got a superview of your scroll view which isn't resizing correctly. You could verify this by logging [myScrollView superview] and seeing if that view is resizing as you expect.
If the superview is not resizing, then it won't pass touches down to your scrollview, which explains the behaviour you're seeing. (This also explains why it resizes when you set is autoresizing mask.)
have you tried using the following method on the object?
[_yourView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];

Resources