After adding constrain scrolling not work - ios

i am trying to add button inside the scrollview with center constrain,
constrain working but scroll not working scroll become stuck,
Anyone can help me where is mistake,
-(void)viewDidLoad{
scrllview = [[UIScrollView alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]];
scrllview.backgroundColor = [UIColor orangeColor];
self.view=scrllview;
[scrllview setContentSize:CGSizeMake(300, 1000)];
submitButton = [UIButton buttonWithType:UIButtonTypeCustom];
[submitButton setTitle:#"connect" forState:UIControlStateNormal];
[submitButton.titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue-Bold" size:14.0]];
[submitButton addTarget:self
action:#selector(myMethod:)
forControlEvents:UIControlEventTouchUpInside];
submitButton.backgroundColor = [UIColor blackColor];
submitButton.translatesAutoresizingMaskIntoConstraints = NO ;
[scrllview addSubview:submitButton];
NSLayoutConstraint *constraint = [NSLayoutConstraint
constraintWithItem:submitButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:scrllview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[scrllview addConstraint:constraint];
constraint = [NSLayoutConstraint
constraintWithItem:submitButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:scrllview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f];
[scrllview addConstraint:constraint];
}

While you are using scrollview with autolayout, you should not use contentsize.
You can create a view inside scroll view, which should have your required height and constraint relative to scrollview. You can add your button inside that view.
It will work. I have implemented it with xib. Same issue while adding control directly in scrollview. I used view inside scrollview and added required control to view.
Auto layout UIScrollView with subviews with dynamic heights

Related

Autolayout inside UIBarButtonItem's custom view

I am having a strange problem with UIBarButtonItem. I am creating one with a custom view, and the view is of my own MyCustomView type. It contains couple of labels and some other subviews. Whenever I use autolayout in this custom view class to lay out the subviews - the button is displayed on top-left corner of the screen! You can see it in the picture below - MyCustomView just has one subview with gray background and I use autolayout to stretch it to fill the parent MyCustomView:
When I don't use autolayout everything is fine and the button is displayed normally:
Can anyone explain me what is going on here and am I allowed to use autolayout in custom views which are going to be put in UIBarButtonItems (maybe not on the topmost level) ?
UPDATE: this happens after I do
self.translatesAutoresizingMaskIntoConstraints = NO;
in MyCustomView - in the top view which should be placed in bar button. I am doing it to make the system call my intrinsicContentSize method. I guess using the old sizeThatFits: instead would still be ok.
UPDATE 2: Here is the test code:
UIControl *cus = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 22, 22)];
// uncomment the following line to mess everything
//cus.translatesAutoresizingMaskIntoConstraints = NO;
cus.backgroundColor = [UIColor redColor];
UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = #"Q";
[label sizeToFit];
label.font = [UIFont systemFontOfSize:18];
[cus addSubview:label];
NSLayoutConstraint *centerX1 = [NSLayoutConstraint constraintWithItem:cus
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:label
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
NSLayoutConstraint *centerY1 = [NSLayoutConstraint constraintWithItem:cus
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:label
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[cus addConstraints:#[centerX1, centerY1]];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:cus];
controller.navigationItem.rightBarButtonItem = barButton;
I would be happy to get explanations to understand what is going on.

UIScrollView with Auto Layout Constraints: Auto Content Size Calculation

I'm having troubles with UIScrollView using auto layout constraints. I have the following view hierarchy, with constraints set through IB:
- ScrollView (leading, trailing, bottom and top spaces to Superview)
-- ContainerView (leading, trailing, bottom and top spaces to ScrollView)
--- Button 1 (full width, **top space to ContainerView**)
--- Button 2 (full width, below Button 1)
--- Button n (full width, below Button n-1, **bottom space to ContainerView**)
I want a simple scrollabel list of buttons. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor redColor]];
[self.contentView setBackgroundColor:[UIColor yellowColor]];
UIView *lastView= self.contentView; // use for top constraint
NSInteger topBottomMargin= 10, leftRightMargin= 16;
for (int i=0; i<10; i++) {
UIButton *button= [UIButton buttonWithType:UIButtonTypeSystem];
button.translatesAutoresizingMaskIntoConstraints= NO;
[button setTitle:[NSString stringWithFormat:#"Button %d", i] forState:UIControlStateNormal];
[self.contentView addSubview:button];
// add constraints
// top
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:lastView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:button
attribute:NSLayoutAttributeTop
multiplier:1.0 constant:-topBottomMargin]];
// left
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeLeading
multiplier:1.0 constant:-leftRightMargin]];
// right
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeTrailing
multiplier:1.0 constant:leftRightMargin]];
lastView= button;
}
// bottom
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:lastView
attribute:NSLayoutAttributeBottom
multiplier:1.0 constant:topBottomMargin]];
}
It seems the height of contentView is 0! But there are constraints both for top and bottom of it. It should be like this:
But with my code it's like this. Any Help would be great.
You can add constraint to container view to scroll view as Equal height & equal width. Also when you add constraint to buttons don't forget add bottom constraints to buttons as it will decide the end of scroll view(content size).
Since you are using auto-layout constraints on the contentView, it's height (frame) will be zero in the viewDidLoad method. You should move your code into the viewDidLayoutSubviews method and try to add your buttons there.
You should get the height of the contentView there. Please let me know if that works. Hope this helps.
See this question for reference: iOS AutoLayout - get frame size width
I don't think we can't add auto layout directly to a ContainerView inside ScrollView with Intrinsic Size as Default, so I add ContainerView as subview programmatically:
- (void)viewDidLoad{
[super viewDidLoad];
self.contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self.scrollView addSubview:self.contentView];
//Then add your button here as normal.
//...
}
And Gurtej Singh is right, we have to update the frame in the viewDidLayoutSubviews:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
//Don't for get to update your self.scrollView.contentSize if you want to able to scroll
//...
//Update your contentView frame based on scrollview frame and self.scrollView.contentSize.
self.contentView.frame = self.scrollView.bounds or ....;
}
I just want to help, it might not a good solution, but it work for me.
I found the solution i was looking for here:
[super viewDidLoad];
UIScrollView* sv = [UIScrollView new];
sv.backgroundColor = [UIColor whiteColor];
sv.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sv];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[sv]|"
options:0 metrics:nil
views:#{#"sv":sv}]];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[sv]|"
options:0 metrics:nil
views:#{#"sv":sv}]];
UILabel* previousLab = nil;
for (int i=0; i<30; i++) {
UILabel* lab = [UILabel new];
lab.translatesAutoresizingMaskIntoConstraints = NO;
lab.text = [NSString stringWithFormat:#"This is label %i", i+1];
[sv addSubview:lab];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(10)-[lab]"
options:0 metrics:nil
views:#{#"lab":lab}]];
if (!previousLab) { // first one, pin to top
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(10)-[lab]"
options:0 metrics:nil
views:#{#"lab":lab}]];
} else { // all others, pin to previous
[sv addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[prev]-(10)-[lab]"
options:0 metrics:nil
views:#{#"lab":lab, #"prev":previousLab}]];
}
previousLab = lab;
}
// last one, pin to bottom and right, this dictates content size height
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[lab]-(10)-|"
options:0 metrics:nil
views:#{#"lab":previousLab}]];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[lab]-(10)-|"
options:0 metrics:nil
views:#{#"lab":previousLab}]];
// look, Ma, no contentSize!

iOS - Pure AutoLayout and UIScrollView not scrolling

This is my first time using UIScrollViews with a pure Autolayout approach. This is what the view hierarchy looks like
view
-scrollview
--view1
--view2
--view3
scrollview should contain view1|view2|view3 in that order.
I set the scrollviews width, height, centerx and bottom space to superview. The view1, view2 and view3 that are created all have their width and height constraints setup in their updateConstraints method. Additionally, some constraints are provided in code. What is the reason this scrollview is not scrolling from left to right? I have read literally all of the guides I can find online about creating and adding subviews to a UIScrollView programmatically with auto layout. I found some mention about having to provide four different constraints, leading, trailing, top and bottom for each view added as a subview to the scrollview. Are these the only NSLayoutAttributes that one can specify? How do attributes such as NSLayoutAttribueLeft or NSLayoutAttribueRight relate? I have read documentation on Apples website as well, specifically https://developer.apple.com/library/ios/technotes/tn2154/_index.html. I am attaching the setup I currently have. Everything is done via code.
- (void)viewDidLoad
{
[super viewDidLoad];
self.dataSource = #[ [[PCCGenericRating alloc] initWithTitle:#"Easiness"
andMessage:#"WHAT A JOKERRRR"
andVariatons:#[ #"very easy", #"easy", #"moderate", #"hard", #"very hard"]],
[[PCCGenericRating alloc] initWithTitle:#"Joker"
andMessage:#"WHAT A JOKERRRR"
andVariatons:#[ #"very easy", #"easy", #"moderate", #"hard", #"very hard"]],
[[PCCGenericRating alloc] initWithTitle:#"Difficulty"
andMessage:#"YOu are not difficult at all"
andVariatons:#[ #"very easy", #"easy", #"moderate", #"hard", #"very hard"]]
];
[self initView];
}
- (void)initView {
CGFloat navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
CGFloat heightDifference = navigationBarHeight + statusBarHeight;
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.delegate = self;
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
self.scrollView.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.scrollView];
//setup constraints
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0f
constant:-heightDifference]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0]];
[self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PCCGenericRating *rating = (PCCGenericRating *)obj;
PCCGenericRatingView *ratingView = [self createViewWithRating:rating];
[self.scrollView addSubview:ratingView];
int multiplier = (idx == 0) ? 1 : (int) (idx + 1) ;
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:ratingView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterX
multiplier:multiplier
constant:0.0f]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:ratingView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f]];
}];
}
- (PCCGenericRatingView *)createViewWithRating:(PCCGenericRating *)rating {
PCCGenericRatingView *view = [PCCGenericRatingView genericRatingViewWithTitle:rating.title andMessage:rating.message];
return view;
}
Upon printing out the scrollview constraints, they look okay to me:
po self.scrollView.constraints
<__NSArrayM 0x115b051f0>(
<NSLayoutConstraint:0x1145d9290 PCCGenericRatingView:0x114579880.centerX == UIScrollView:0x11458d4b0.centerX>,
<NSLayoutConstraint:0x1145d9410 PCCGenericRatingView:0x114579880.centerY == UIScrollView:0x11458d4b0.centerY>,
<NSLayoutConstraint:0x1145d9dd0 PCCGenericRatingView:0x1145d9560.centerX == 2*UIScrollView:0x11458d4b0.centerX>,
<NSLayoutConstraint:0x1145d9e40 PCCGenericRatingView:0x1145d9560.centerY == UIScrollView:0x11458d4b0.centerY>,
<NSLayoutConstraint:0x1145da6b0 PCCGenericRatingView:0x1145d9e90.centerX == 3*UIScrollView:0x11458d4b0.centerX>,
<NSLayoutConstraint:0x1145da730 PCCGenericRatingView:0x1145d9e90.centerY == UIScrollView:0x11458d4b0.centerY>
)
Here is a screenshot of what it looks like:
I find it odd that the last element in the datasource is the first view controller showing up in the scrollview, when it should be the last view. It also doesn't scroll left to right as it should.
Make sure your top_constraint for the view1 and bottom_constraint for view3 will be as per your scrollView's constraints. Otherwise scrollview's contentSize: {0, 0}.
Wherever you are printing your constraints, try printing scrollview.contentSize, it will likely be 0,0 and that is where your problem is. As far as I know, and as you mentioned in your post, you have to explicitly set the subviews of a scrollview to the scrollviews top bottom left and right constraints. Setting these automatically sets the contentSize of the scrollview which will enable it to scroll. It looks like you are only setting centerX and centerY constraints which will not set the scrollviews contentSize to what you need.
Try setting these programatically (this is pseudocode but you get the idea):
view1.topConstraint = scrollView.topConstraint
view1.leftConstraint = scrollView.leftConstraint
view3.bottomConstraint = scrollView.bottomConstraint
view3.rightConstraint = scrollView.rightConstraint
If you set all of those correctly, your scrollview will scroll properly. Just remember to check the contentsize, and if the contentsize is 0,0 then your constraints aren't properly set up.

How to add label programmatically and position it with auto layout programmatically

I'm trying add a label to a UIScrollView. I'm adding a top constraint and a leading constraint.
The label is not appearing.
Here is my code.
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.label.translatesAutoresizingMaskIntoConstraints = NO;
self.label.backgroundColor = [UIColor clearColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.textColor=[UIColor whiteColor];
self.label.text = #"Hello";
[self.imageCarouselScrollView addSubview:self.label];
[self bringSubviewToFront:self.label];
self.titleLabelTopConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20];
NSLayoutConstraint *titleLeadingConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:20];
[self addConstraints:#[self.titleLabelTopConstraint,titleLeadingConstraint]];
You have to include a constraint to the right (for horizontal scrolling) or bottom (for vertical scrolling) of the scroll view so that it can deduce the content size.
I try comment your code:
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; //if 'translatesAutoresizingMaskIntoConstraints=NO' frame not work work anymore. Use CGRectZero instead
self.label.translatesAutoresizingMaskIntoConstraints = NO;
self.label.backgroundColor = [UIColor clearColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.textColor=[UIColor whiteColor];
self.label.text = #"Hello";
[self.imageCarouselScrollView addSubview:self.label]; //Your self.label added on 'self.imageCarouselScrollView' but your constraints added on self
[self bringSubviewToFront:self.label]; // ??? Why?
self.titleLabelTopConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20]; //it constrain means: "self view top edge equal to self.imageCarouselScrollView bottom + offset 20 "
NSLayoutConstraint *titleLeadingConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:20];//it constrain means: "self view Leading edge equal to self.imageCarouselScrollView Trailing + offset 20 "
[self addConstraints:#[self.titleLabelTopConstraint,titleLeadingConstraint]];
And now i have few questions:
Why constraints for self.label?? Because after translatesAutoresizingMaskIntoConstraints=no it frame equals 0; You didn't see label anymore.
You have 2 constraints what about other edges????
No question, council, try use 'constraintsWithVisualFormat:options:metrics:views:'

Autolayout stops UITapGestureRecognizer?

I setup a UIImageView to accept tap gesture, which is tapped, the button shall go hidden and shows a UIActivityIndicatorView at the same position. The logic is very simple. but I have two problems:
I need to add either [fb setTranslatesAutoresizingMaskIntoConstraints:NO]; or [loading setTranslatesAutoresizingMaskIntoConstraints:NO]; to avoid constraint conflict. in order to be safe, i added both. seems UIImageView and UIActivityIndicatorView have their own builtin constraints:
"<NSLayoutConstraint:0x8d69e80 UIImageView:0x8d68700.centerX == UIView:0x8d626f0.centerX>",
"<NSLayoutConstraint:0x8d6a0f0 UIActivityIndicatorView:0x8d629b0.centerX == UIView:0x8d626f0.centerX>",
"<NSAutoresizingMaskLayoutConstraint:0x8b48d30 h=--& v=--& UIActivityIndicatorView:0x8d629b0.midX == + 18.5>",
"<NSAutoresizingMaskLayoutConstraint:0x8b495f0 h=--& v=--& UIImageView:0x8d68700.midX == + 60>"
I have to comment off either the line [fb
setTranslatesAutoresizingMaskIntoConstraints:NO]; or [loading
setTranslatesAutoresizingMaskIntoConstraints:NO];. otherwise, the UITapGestureRecognizer doesn't work anymore, why?
code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// setup the loading activity indicator;
loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.view addSubview:loading];
loading.hidden = YES;
// setup the fb button
fb = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"facebook.png"]];
fb.userInteractionEnabled = YES;
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] init];
[tap addTarget:self action:#selector(login:)];
[fb addGestureRecognizer:tap];
[self.view addSubview:fb];
fb.hidden = YES;
NSLayoutConstraint *c;
c = [NSLayoutConstraint constraintWithItem:fb
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:fb
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:loading
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:loading
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[self.view addConstraint:c];
[fb setTranslatesAutoresizingMaskIntoConstraints:NO];
[loading setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
}
You need to call setTranslatesAutoresizingMaskIntoConstraints:NO because the autoresizing mask gets converted to constraints which conflict with the autolayout system. You usually cannot add auto layout constraints to views with autoresizing masks constraints or you'll get into incompatible constraints.
The main issue in your case is that the width and height of those issues cannot be determined. You need to add width and height constraints as well. The layout can't be determined using the centering constraints if the auto layout system can't calculate them.

Resources