UIView in UIScrollView not scrolling - ios

I am using the Xcode storyboard interface builder and I created a view controller with a UIScrollView that only has a single child UIView. This child UIView has many labels/buttons etc attached and exceeds the screen size height wise, however when I run my app, the view does not scroll for some reason.
Here is a picture of the ViewController structure:
What am I doing wrong?

You need to set the contentSize property of the UIScrollView. You can do this programatically (e.g. in viewDidLayoutSubviews) or under User Defined Runtime Attributes in the identity inspector panel in interface builder.
The actual size is dependent on your content. You can calculate it programatically using something like:
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect;
which will just find the smallest CGRect that contains all the frames of the subvies of the UIScrollView.

You can set the contentSize programmatically, but you don't need to and shouldn't have to. Instead, ensure that you have enough constraints that the scroll view's child view can calculate an exact total width and height. If you don't have enough constraints defined to do this, then Interface Builder will show you an error.

Related

Add UIScrollView programmatically in a ViewController that contains a smaller UIView with objects

I have an UIViewcontroller. I have a smaller UIVIew in this UIVIewController. Now i am trying to add an UIScrollView programmatically that should contain the smaller UIView so i can scroll the smaller view up and down. The smaller UIView is already created using the interface builder of xcode. So now i use the following code to add the scrollView and then add the smaller View in the scrollView. The scrollView should have the same size in width as the smaller View.
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(self.smallerView.frame.origin.x, self.smallerView.frame.origin.y, self.smallerView.frame.size.width, self.smallerView.frame.size.height)];
[self.scrollView setContentSize:CGSizeMake(self.smallerView.bounds.size.width, self.smallerView.bounds.size.height*1.2)];
[self.scrollView addSubview:self.smallerView];
[self.view addSubview:self.scrollView];
The weird thing is that the objects that are contained in the smaller UIView are not inside the bounds of the UIScrollView. What am i missing? Do i have to add constraints for the smaller UIView programmatically? Any help appreciated.

UiScrollView Incorrect Height (Without AutoConstraint)

Searched a lot on stack overflow, but didn't find any solution that works for us.
What we have are a couple of Views and UILabels and UIButtons in UIScrollView as below format. On Click of button we are hiding couple of views and labels and trying to recalculate UIScollView height.
UIScrollView
-->UIView
-->UIView2
-->UIView3
-->UILabel1
-->UILabel2 ( Please note these labels are not inside UIView, they are directly added to scrollview. Is this correct approach or they should be added inside a UIView?)
-->UITextField (Directly added to scrollview)
-->UITextField1 (Directly added to scrollview)
-->UIButton ( On Click of Button above textfields and labels are hidden or shown based on business logic)
When we try to reset size of UIScrollview on UIButton click it doesn't calculate height correctly. Tried below solution shared by lot of answers in stack overflow
Is the problem with labels and buttons added directly to UIScrollView?
Is there better way to set height of UIScrollview correctly?
We don't want to use AutoConstraint
CGRect contentRect = CGRectZero;for (UIView *view in uiScrollViewObj.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
uiScrollViewObj.contentSize = contentRect.size;
No it's not, in fact UILabels and UIButtons are UIViews.
I think you are confusing two concepts. The UIScrollView height is the height of the viewport (the visible part of the scrollview). What you want to change is the contentSize height that is the height of the whole content which you want to scroll through (I don't know if I have explain myself clear).
If the structure is the way you said it, so the UIButton is the closest element to the button, you should move its frame and place it upper, otherwise the contentSize is always gonna be the same.
Besides that, your code is iterating through all the views of the scrollview and those are not only the ones you added but also the ones that Apple inserted.
The best way to calculate the contentsize dynamically is to sum scrollview subviews y position and their height. Something like this should work:
CGFloat viewY, maxY=0;
for (UIView *view in uiScrollViewObj.subviews) {
if (view.hidden) continue;
viewY = view.frame.origin.y + view.frame.size.height;
maxY = (viewY > maxY) ? viewY : maxY;
}
[uiScrollViewObj setContentSize:CGSizeMake(uiScrollViewObj.frame.size.width, maxY)];

How to create ScrollView with AutoLayout in Xcode 6.3

How to create ScrollView with AutoLayout in Xcode 6.3. While I create the scroll view it takes 600X 600 screen and doesnt change the view size according to the screen orientation. What is the best waay to acheive the ScrollView with AutoLayout . I have following code inside ViewDidLoad
[mainScrollView addSubview:contentView];
[mainScrollView setContentSize:CGSizeMake(320,800)];
contentView.frame = CGRectMake(0, 0, [Util window_width], 800);
I have following Nib file as shown below
I have got the contentview
UIScrollView is placed over UIViewController
Give the scroll view spacing constraints to all sides of the controller's view, then it will be whatever size the screen is.
You should never just drop a view into a controller without adding your own constraints when you're using the wAny hAny size class; the system will add constraints for you, and they will be origin at {0,0}, and width and height of 600 (assuming that you made the view full size) which doesn't correspond to any actual device.

iOS View is not expanding the way I want it

I have a UIViewController with a UICollectionView and a UIView at the bottom. The way I put it together is displayed in the image below
The yellow square is the UICollectionView and the red is the UIView. This works out just fine. But now I want to resize the UIView because it sometimes contains more info and needs to be bigger. So I tried this:
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height + 10)];
But this expands the UIView at the bottom and it is not visible. I guess this is because I do not have the correct constraints? I also tried to subtract the origin.y with the same amount and this works only the UICollectionView doesn't get resized with the new height. So how do I tackle this problem?
If you are using autolayout, you should not be setting the frame from your code. Instead you should modify the constant of a constraint that is causing your view to be the incorrect size. You can have an IBOutlet to that constraint and you can change it's constant property. Then call setNeedsLayout on your view controller's view
When setting constraints on your storyboard or in a xib file, animations perform animations on the constraints instead of the sizes and positions.
First create a outlet reference of the constraint which will change (in your case the top space of your UIView to the top layout guide) in the header file of your view controller.
When you want to animate a view, you now have to update its constraints and ask to layout the views.
For example :
[UIView animateWithDuration:0.2
animations:^{
viewYConstraint.constant -= 44;
[self.view layoutIfNeeded];
}
]
//Now don't forget to update constraints
[self.view updateConstraints];

Can't change UITextView frame size programmatically

I've insert an UITextView in a view with Interface builder, now I would like to change its frame size so it fits the content programmatically. The problem is that the size seems locked and unchangable from code because of the constraints. If I disable in file inspector use auto-layout every object gets the constraints removed, but I only want to change the UITextView not the other objects.
[textview setFrame:CGRectMake(x,y,w,h)]; // This doesn't do anything to the uitextview
If you're using constraints, then you must use constraints to change the UITextView's size. Set up outlets in the nib to get access from your code to the constraints you need to change. You can set a constraint's constant in real time, and this is usually sufficient.
Just to clarify the reasons for this: you cannot change a view's frame if it is being positioned by constraints. Well, you can, but it's fruitless and it's bad practice. This is because the constraints themselves will be used by the layout system to change the view's frame for you! Thus, you can change the frame, but the layout system will then read and resolve the constraints and change the frame back again.
Think of constraints as a "to-do list" for the layout system. Constraints do nothing in and of themselves; they are just a list of rules. It is the layout system that does the work (when layoutSubviews is called). Every time layout is needed, the layout system comes along, reads the constraints, works out how to obey them, and does so - by setting the frames of your views. You need to work with that system, not against it.
All of UIViews and classes are inherited from UIView have same property is: "Lock" in XIB file.
If you want to change frame of those views. You must set Lock is "Nothing"
If you don't care to become a constraint expert, do it like this (in your view controller.)
#property UITextView *textView;
//Create UITextView on the fly in viewWillAppear
rect = CGRectMake(194., 180., 464., 524.);
_textView = [[UITextView alloc] initWithFrame:rect];
[self.view addSubview:_textView];
//Now you can resize it at will
CGRect oldFrame = _textView.frame;
CGRect newFrame = oldFrame;
newFrame.size.height += 300;
[_textView setFrame:newFrame];

Resources