Subview will not align trailing edge with its parent UIScrollView

I have a UIScrollView with 2 subviews. I would like one subview to be “aligned aligned” (left justified), where its leading edge connects to the leading edge of the scrollview. I would like the other subview to be “top-aligned” (right-aligned), where its trailing edge connects to the trailing edge of scrollview.

For some reason, autolayout unexpectedly places the second, involuntarily aligned subview outside the scrollview, on the leading (left) side of the other subview, so that the trailing edge of the subview is aligned with the rising edge of the scrollview.

I am trying to do this programmatically. The code is below. I use 2 shortcuts for 2 subzones. The alpha label is correctly aligned, but the beta label does not align in length as it should.

This also happens if I try to use left and right alignment, and not as leading and ending. The right-aligned label appears in the same wrong place as the label with the aligned end.

I read iOS 6 release notes and answers here and elsewhere many times, and I just don't know why this is happening.

In the view controller:

- (void) viewDidLoad { [super viewDidLoad]; // Create and configure the scroll view. UIScrollView * scrollView = [[UIScrollView alloc] init]; [scrollView setTranslatesAutoresizingMaskIntoConstraints:NO]; // For debugging. [scrollView setClipsToBounds:NO]; scrollView.layer.borderColor = [UIColor redColor].CGColor; scrollView.layer.borderWidth = 1.0; [[self view] addSubview:scrollView]; // Layout scrollview. // Horizontal: leading edge to superview leading edge, with indent. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:20.0]]; // Horizontal: trailing edge to superview trailing edge, with indent. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-20.0]]; // Vertical: top edge to superview top edge, with indent. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0]]; // Vertical: bottom edge to superview bottom edge, with indent. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20.0]]; // Create and configure first label which should be leading-aligned with scrollview. UILabel * labelAlpha = [[UILabel alloc] init]; [labelAlpha setTranslatesAutoresizingMaskIntoConstraints:NO]; [labelAlpha setText:@"Alpha"]; [scrollView addSubview:labelAlpha]; // Layout first label. // Horizontal: leading edge to scrollview leading edge. [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:labelAlpha attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]]; // Vertical: top edge to scrollview top edge. [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:labelAlpha attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; // Create and configure second label which should be trailing-aligned with scrollview. UILabel * labelBeta = [[UILabel alloc] init]; [labelBeta setTranslatesAutoresizingMaskIntoConstraints:NO]; [labelBeta setText:@"Beta"]; [scrollView addSubview:labelBeta]; // Layout second label. // Horizontal: trailing edge to scrollview trailing edge. [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:labelBeta attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]]; // Vertical: top edge to scrollview top edge. [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:labelBeta attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; } 

For reference, exiting a view controller from a recursiveDescription view supports misalignment:

 2013-07-15 22:04:23.892 Middleman[5669:907] <UIView: 0x20872960; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = RM+BM; layer = <CALayer: 0x20871e60>> | <UIScrollView: 0x208718a0; frame = (20 20; 440 280); gestureRecognizers = <NSArray: 0x20871f20>; layer = <CALayer: 0x208728e0>; contentOffset: {0, 0}> | | <UILabel: 0x20872ab0; frame = (0 0; 44 21); text = 'Alpha'; clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x20872b90>> | | <UILabel: 0x208730e0; frame = (-36 0; 36 21); text = 'Beta'; clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x20873170>> 
+6
source share
3 answers

I struggled with the same problem and finally found a solution. Please note: I do not use objective C, I use MonoTouch (C #), but the principle should be the same.

The problem is that AutoLayout allows restrictions for UIScrollView. For many other views, auto-detection uses rect alignment, which in many cases matches the view frame. However, the UIScrollView apparently uses the size (e.g. width) of the frame if the restriction is concentrated (e.g. centerX), so my subordination is usually concentrated in the UIScrollView, but when adding restrictions to the right-edge, the subview uses the width / height of the contentSize. The problem is that the width of the contentSize in my case was 0 (vertical scrolling only), so right justification meant only justifying the width of the window to width 0, which is why I saw that my subview is on the left.

Normally, I would also allow contentSize to be constrained as well, but in this case only the height of the contentSize was nonzero, as I was scrolling it vertically. I tried to add restrictions in the scroll view to get the contentSize width set correctly, but the only way to do this (while maintaining the necessary restrictions for my page) was as follows:

  • Insert an "empty" UIView as a child of scrollView.
  • Set the width of the UIView to the width of the View container with the highest level (above scrollView) using restrictions
  • Apply a restriction to scrollView so that its right edge should be greater than or equal to the right edge of my empty UIView (similar to the restriction used to set the vertical content to scroll the page).

Now my width of the UIScrollView contentSize is set correctly, and all the elements fit the right edge as expected.

+6
source

My solution is to insert some kind of helperView (e.g. UIView, UITableView) into UIScrollView and apply 6 constraints to helperView:

 - equal width to scrollView - equal height to scrollView - 0 leading space to scrollView - 0 trailing space to scrollView - 0 top space to scrollView - 0 bottom space to scrollView 

You can align other scrollView child views to the edges of the helperView.

+1
source

You can try to use the correct alignment of the text and set the label width limit. Otherwise, the size of the label matches the content.

 CGFloat width = CGRectGetWidth(self.view.frame)-40.0; labelBeta.preferredMaxLayoutWidth = width; //required for multi line wrapping [scrollView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[labelBeta(width)]|" options:0 metrics:@{@"width":@(width)} views:NSDictionaryOfVariableBindings(labelBeta)]]; 
0
source

Source: https://habr.com/ru/post/949512/


All Articles