Center contents of UIScrollview when using autolayout - ios

I'm using autolayout in my project and I have a scrollview that has a button centered in it. I have gotten the scrollview to scroll, but not to take up the entire screen.
I've tried to follow the tutorial here: https://developer.apple.com/library/ios/technotes/tn2154/_index.html, as well as I have checked out a few similar questions on here. The issue is that I want the contents of the scrollview to center, rather than be pinned to the top/bottom/left/right.
Here is my view hierarchy:
Could you please help me out?

You have added constrains between your scroller view and its super view. These constrains determines the frame of the scroll view. You can think of the scroll view as a window, through which you can see the the contents behind. The frame is the just the size of the window. Of course, you can slide the window, which gives you the sights of parts of the contents.
Now you have the size of the window, but you also need to tell Xcode the size of the contents. If you just say put everything in the middle without telling the width, how can Xcode know where is the middle?
So, you have to tell the width (as well as height). Let's think about a simple example, how to center a single label in a scrollview.
You should first pin the edges of the scroll view to its super view just as what you did. After that you should add constraints between the edges of the label and the edges of the scroll view, besides, you should also add the with and the height constraints of the label.
The leading space, the trailing space and the width together give the with of the contents, while the top space, bottom space and the height together give the height of the contents.
|---leading space---|label width|---trailing space---|
|---------- content with of the scroll view -------------|
But you may want to set the with of the content view equal to the with of your screen, then you need to do some programming. Set there outlet properties in you code
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *trailingSpace;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpace;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *width;
In your viewWillLayoutSubviews do this
CGFloat contentWidth = self.view.frame.size.width;
CGFloat horiPadding = (contentWidth - self.width.constant) / 2;
_trailingSpace.constant = horiPadding;
_leadingSpace.constant = horiPadding;
Now you the label is at the horizontal center of you scroll view! Your scroll view has already knew the with of its contents, so you don't need to do this for any other view you added in your scroll view: you can just add the center constraint.
You can also do the same thing for the height.

Related

scrollview is not scrolling in autolayout xcode 6.4

I am using UIScrollview and top of a UIView but scrolling is not working.
for scrollview i added constraints all the side (0,0,0,0) then i have take container view and adedd constraints for (0,0,0,0) for all side . and one more constraints i added for this container view to View with equal width.
my scrollview hight is 504 and containner hight is 840. i am not getting any warning and suggestion constraints but not able to scroll . what is missing here .Please suggest me .
if you have added constraints properly . then add this
make property or your scrolview and container view as
#property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
#property (weak, nonatomic) IBOutlet UIView *containerview;
then in .m file
#synthesize scrollview,containerview,
then add this
-(void)viewDidAppear:(BOOL)animated
{
[scrollview setContentSize:CGSizeMake(scrollview.frame.size.width, containerview.frame.size.height)];
}
I hope the will solve your issue.
There is no problem with autolayout in x-code 6.4 just try to check that you have properly bind the outlets of scrollview as well as give contentsize to scrollview that how much you would like to scroll your scrollview.
scrollview.ContentSize = CGContentSize(0, height);
--> Give height as float or integer as how much you want to scroll your scrollview.
For the ScrollView to work, reference it to your .h file by CTRL + Dragging the scroll view, and on your .m file add a
scrollView.contentSize(0,doubleTheSizeOfTheViewHeight);
if you want the scroll to be scrollable horizontally do the same with the width.
Hope this helps
Update
Or you can always use this for the storyboard way of doing it:
Storyboard UIScrollView contentSize?
To make UIScrollview scrolling, you have to uncheck checkbox with "Use Auto Layout" from XIB.

UIView in UIScrollView does not adjust width

I have been searching through stackOverflow and whatever google proposes but I wasn't able to get it to work. I am intending to draw a simple 2D Graph in a scrollview, the distance between my datapoints is kStepX and I want the scrollview to be at least the width of the screen, if I have more datapoints it should scroll but no more than 100 points.
I think I have a problem with my Autolayout and sizing the contentWidth, so here is what I have done so far:
I added a UIScrollView with the following constraints:
Leading Space to Superview =0
Top space to superview =0
Height = width of superview
Width = width of superview
I then added a UIView (called GraphView) as a Child with the following constraints:
zero space to all 4 bounds of scrollview
center X and center Y to scrollview
in my GraphViewController I set the contenSize as:
historyScrollView.contentSize = CGSizeMake(MAX(SCREEN_WIDTH,sizeof(data)*kStepX), kGraphHeight);
but it does not scroll!
if I set a fix width in the storyboard the scrollview scrolls further than I have data..
What am I doing wrong?
You should not be setting the contentSize of the scrollView when using auto layout. That should be calculated from your constraints if they are setup correctly.
What you are missing is to set a width and height constraints on the view inside the scrollView. A scrollView determines it's contentSize based on the size the subviews have. Since an UIView does not have an intrinsic size, you will need to add width and height constraints to it, then update it when you need it with the right value
Something like this should work:
innerViewWidthConstraint.constant = MAX(SCREEN_WIDTH,sizeof(data)*kStepX)
innerViewHeightConstraint.constant = kGraphHeight
// You might need to layout the views too
[historyScrollView layoutIfNeeded]
Hope this helps! Good luck :)
Take ScrollView in side in your Main View and give Top,Bottom,Leading,Trailing,Center X and Center Y.
after take GraphView inside you scrollview and also set constrain of GraphView.
set height of GraphView
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *HeightGraphView;
whenEver you set your HeightGraphView then automatically set ScrollView contentSize.
see my demo its working for Vertically scrolling, apply same for Horizontal scrolling.
Demo Vertical Scrolling

constraints problems with containers

OK I have a view-controller that sits in a container of another view.
MainView
View
Someview
ContainerView (contains ContainedViewController)
Otherview
ContainedViewController
ContainedView (height can get resized during run).
UILabel (varying height)
UIView (fixed size, width & height)
Here's the thing... the view in ContainedViewController needs to get resized at runtime. It contains a label (that can grow depending on the text in it) and a static view directly below it, that never changes size
So, I have a constraint on the UILabel for it's height, and I change that at runtime, depending on how big it needs to be. There's a vertical constraint between the label and the fixed-view, and all of the "standard" constraints to the main superview.
When I run, though, I get "unable to simultaneously satisfy constraints", followed by the constraint log. Among the conflicting constraints are my new UILabel height, and then the height of ContainedView. I get a "UIView-Encapsulated-View-Height" problem with the ContainedView.
Apparently, "ContainedView"'s height is being dictated by the height of MainView's ContainerView.
What I want is for the ContainedView's height to change when the UILabel's height changes, and then have the propagate back up the containers, all the way to MainView. But I can't seem to get this to work.
How can I get the superview, and it's container view to resize when I change the size of my label?
In your main view controller, declare the following override:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Layout the container's content and get its resulting size
[self.containedViewController.view layoutIfNeeded];
CGSize containedViewSize = [self.containedViewController contentSize];
// Now, use containedViewSize to set constraints on the view controller.
self.containerHeightConstraint.constant = containedViewSize.height;
self.containerWidthConstraint.constant = containedViewHeight.width;
}
Then, in your contained view controller, declare these properties:
#property (nonatomic, weak) IBOutlet UIView * contentView;
#property (nonatomic, weak) UIViewController * mainViewController;
In your storyboard make contentView a subview of the contained view controller's main view. Pin it with constraints to the main view's top left corner. Put whatever content you want in contentView, including constraints that determine contentView's size. (DON'T pin the contentView's length and width to the main view, however; that will cause conflicting constraints you described above.)
mainViewController should be set when preparing for the embed segue that sets up the container view controller.
And this method:
- (CGSize)contentSize {
return self.contentView.frame.size;
}
Now, whenever you do something in the container view controller that affects the size of contentView, make the following call:
[self.mainViewController.view setNeedsLayout];
Sorry this isn't simpler, but it's the best solution I've found to this problem so far.

iOS how to make dynamic width / autolayout of UIView according to UILabel within it

I am struggling with maybe a bit of a rookie issue. I have a UIView within which I display some price. I want the UIView to be of a dynamic width according to the price, if its 1 Euro, then it will be e.g. 20pt, if its 2300 Euro, then it will be like 50pt in width.
I was trying to use the storyboard's constraints but without luck. Is it possible to do it within storyboard or do I have to calculate the width of UILabel and then set the width of UIView programmatically?
Thank you in advance.
Yes, you can do this in the storyboard. Add a label to your view and pin it to the left and right edge (top and bottom if you want also). Give the view constraints to its superview in the x and y directions, but do not give it a width constraint (it will need a height constraint if you didn't pin the top and bottom of the label to it). The view should then expand with the label depending on its content.
In general, auto layout is performed in a top-down fashion. In other words, a parent view layout is performed first, and then any child view layouts are performed. So asking the system to size the parent based on the child is a bit like swimming upstream, harder to do, but still possible with some work.
One solution is to use the intrinsic size of a view.
For example, a UILabel has an intrinsic size based on the text in the label. If a UILabel has a leading constraint and a top constraint, but no other constraints, then its width and height are determined by its intrinsic size.
You can do the same thing with a custom view class that encloses a UILabel. By setting the intrinsic size of the custom view class based on the intrinsic size of the UILabel, you get a view that automatically resizes based on the text in the label.
Here's what the code looks like for the custom class. The .h file defines a single property text. The .m file has an IBOutlet to the child label. Setting and getting the text property simply sets or gets the text from the label. But there's one very important twist, setting the text invalidates the intrinsic size of the parent. That's what makes the system adjust the size of the parent view. In the sample code below the parent is sized to have an 8 pixel margin all around the UILabel.
SurroundView.h
#interface SurroundView : UIView
#property (strong, nonatomic) NSString *text;
#end
SurroundView.m
#interface SurroundView()
#property (weak, nonatomic) IBOutlet UILabel *childLabel;
#end
#implementation SurroundView
- (void)setText:(NSString *)text
{
self.childLabel.text = text;
[self invalidateIntrinsicContentSize];
}
- (NSString *)text
{
return( self.childLabel.text );
}
- (CGSize)intrinsicContentSize
{
CGSize size = self.childLabel.intrinsicContentSize;
size.height += 16;
size.width += 16;
return( size );
}
#end
Creating the IBOutlet to the childLabel can be a little tricky, so here's the procedure
drag out a UIView into the storyboard
use the Identity inspector to change the class to SurroundView
drag out a UILabel and add it as a subview of the SurroundView
select the label, and open the assistant editor
show SurroundView.m in the assistant
drag from the open circle to the label as shown below
All that's left is to get the constraints right. The constraints for the label should look like this
The constraints for the SurroundView should be as shown below. The key point is that the Intrinsic Size should be set to Placeholder to avoid the warnings about missing constraints.
Place the label inside the view and pin its TOP , BOTTOM , TRAILING and LEADING edges to the labels superview. Note that you do not specify the width constraint. Now add a height and width constraint to the view. Make an outlet to the width constraint and when the price changes set the view's width constraint's constant to your desired value. Since the label is pinned to the view it will expand too.

UIScrollView in Interface Builder not working

I originally had a normal view with a bunch of stuff in it, and I want that view to be an UIScrollView, so I created a new ScrollView and dragged everything over. The view is not scrolling.
After looking around - I unchecked use autolayout, but that didn't work. I also realize that this could be solved by setting contentSize, but I have access to this view through a variable that is of type UIView, and not UIScrollView. In other words I would be doing -
self.someController.view.contentSize = //something
where self.someController.view is only an UIView and contentSize is not a property of UIView(or at least that's what I'm seeing- I get compiler warnings).
Why is this scroll view not scrolling?
EDIT -
So I stupidly forgot I can cast - I did that, but it's still not working -
UIScrollView* basicCardView = ((UIScrollView *)self.detailController.view);
basicCardView.contentSize = CGSizeMake(basicCardView.frame.size.width * 12,
basicCardView.frame.size.height);
You need to connect your scrollview to Iboutlet var in .m .
Create var in your interface:
IBOutlet UIScrollView *scrollview;
And connect to your scrollview in storyboard, then you can set contentsize.
[scrollview setContentSize:CGSizeMake(2000,200)];
Elto has it correct. To elaborate: In your view controller .m say it's called MyViewController:
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#end
Go back to storyboard, select your view controller and select the connections tab (last one on the upper right). You should now see an outlet called scrollView. Drag a connection from that outlet to the scroll view that you added to the scene.
Now the content size code can be written. Just to get it working, use large constants in content size, like:
self.scrollView.contentSize = CGSizeMake(1000, 1000);
The size you're setting in the post (on the wrong view) looks like it's just the size of one of the subviews. You want the content size of the scroll view to be more like a multiple of the scrollView's size. You want the rectangle it can scroll within to at least encompass the frame (not the bounds) of every subview it contains.

Resources