Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIView with Auto layout, get his size

I have one UIView witch is populated with content programmatically. Layout in this UIView is made using Auto-layout.

This view needs to be subview of one UIScrollView, and it needs to scroll vertically.

I have code like this:

// self.scrollview is defined in IB and it has constraints to edges (margin:0 0 0 0)

UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, MAXFLOAT)];
[contentView setTranslatesAutoresizingMaskIntoConstraints:YES];

// Then I call some my parser which add subviews to the contentView and layout them using constraints.

[self.scrollview addSubview:contentView];
[contentView setNeedsLayout];
[contentView layoutIfNeeded];

// Now, I need to know height of the contentView to be able to set contentSize to self.scrollview

// UPDATE

Ok, I have this UILabel, added to self.content which is UIView created with: [[UIView alloc] initWithFrame:CGRectMake(self.layoutMargin, self.layoutMargin, 1024 - self.layoutMargin*2, 100)]);

This self.content view is just container for me, which needs to be placed in some UIScrollView. I need the height of the self.content to set contentSize of the UIScrollView.

[self.content setTranslatesAutoresizingMaskIntoConstraints:YES];

[self.content setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.content setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];

UILabel *textlabel = [[UILabel alloc] init];
UIFont *font;


font = [UIFont fontWithName:@"InterstatePlus-Regular" size:16];

UIFont *bold;

bold = [UIFont fontWithName:@"InterstatePlus-Bold" size:16];
NSDictionary *style = @{
                        @"$default" : @{NSFontAttributeName  : font},
                        @"b"        : @{NSFontAttributeName  : bold},
                        @"em"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Italic" size:14]},
                        @"h1"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:48]},
                        @"h2"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:36]},
                        @"h3"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:32]},
                        @"h4"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:24]},
                        @"h5"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:18]},
                        @"h6"       : @{NSFontAttributeName  : [UIFont fontWithName:@"HelveticaNeue-Medium" size:16]}
                        };
[textlabel setNumberOfLines:0];



NSError *error = nil;
NSString *string = @"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing <br>Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type<br> and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
NSString *replacedString = [string stringByReplacingOccurrencesOfString:@"<br>" withString:@"\n"];
NSAttributedString *attributedString = [SLSMarkupParser attributedStringWithMarkup:replacedString style:style error:&error];
NSMutableAttributedString *mutAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];

NSInteger strLength = [attributedString length];
NSMutableParagraphStyle *paragraphstyle = [[NSMutableParagraphStyle alloc] init];
[mutAttributedString addAttribute:NSParagraphStyleAttributeName
                            value:paragraphstyle
                            range:NSMakeRange(0, strLength)];

if (mutAttributedString) {
    textlabel.attributedText = mutAttributedString;
}


[textlabel setTranslatesAutoresizingMaskIntoConstraints:NO];

[textlabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[textlabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];


textlabel.textAlignment = NSTextAlignmentLeft;

[textlabel setTextColor:[UIColor blackColor]];

[textlabel setBackgroundColor:[UIColor clearColor]];
textlabel.lineBreakMode = NSLineBreakByWordWrapping;
[textlabel setNumberOfLines:0];
[self.content addSubview:textlabel];

[textlabel mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.content.mas_top).with.offset(0); 
    make.right.equalTo(self.content.mas_right).with.offset(0);
    make.height.equalTo(@1200);
    make.left.equalTo(self.content.mas_left).with.offset(0);
}];
[self.containerView addSubview:self.content];
[self.containerView setBackgroundColor:[UIColor redColor]];
[self.content setBackgroundColor:[UIColor yellowColor]];

CGSize s = [self.content systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
NSLog(@"Size: %f %f", s.width, s.height);

This is Log: Size: 17713.000000 0.000000

And it looks like: http://d.pr/i/Rxku

like image 426
dormitkon Avatar asked Jul 27 '13 20:07

dormitkon


2 Answers

sizeToFit is the wrong API to use if you're using autolayout.

The correct api to use for autolayout is UIView systemLayoutSizeFittingSize:, most likely passing UILayoutFittingCompressedSize. This will return a CGSize which is the minimum size that can bound the view with its specified constraints.

Check this link

EDIT: In response to the additional code that was posted...

I've never used the Masonry library before but it's neat!

UILabels provide an intrinsicContentSize that is large enough to display their text. In order to calculate this size for multi-line text the label needs to know a single dimension that will be fixed, and that is the desired-width dimension via the preferredMaxLayoutWidth property. If you don't provide a preferredMaxLayoutWidth value (defaults to 0), the label calculates an intrinsic content size AS IF it were laying out a single line of text.

In your code you never set the label's preferredMaxLayoutWidth so any layout performed by autolayout that relies on the intrinsicContentSize of the label will not be what you're expecting.

I took your code and distilled it into a new example, which you should be able to copy/paste into a clean viewcontroller subclass:

#import "Masonry.h"

@interface TSViewController ()
@end

@implementation TSViewController
{
    UIScrollView*   _scrollView;
    UIView*         _containerView;

    UILabel*        _titleLabel;
    UILabel*        _contentLabel;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor darkGrayColor];

    // create/configure our scrollview
    _scrollView = [UIScrollView new];
    _scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    _scrollView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
    [self.view addSubview: _scrollView];

    // create/configure our container
    _containerView = [UIView new];
    _containerView.translatesAutoresizingMaskIntoConstraints = NO;
    _containerView.backgroundColor = [UIColor yellowColor];
    [_scrollView addSubview: _containerView];

    // create/configure our content - title and content labels
    _titleLabel = [UILabel new];
    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    _titleLabel.numberOfLines = 1;
    _titleLabel.font = [UIFont fontWithName: @"Courier" size: 80];
    _titleLabel.text = @"Lorem Ipsum";
    _titleLabel.backgroundColor = [UIColor lightGrayColor];
    _titleLabel.textAlignment = NSTextAlignmentCenter;
    [_containerView addSubview: _titleLabel];

    _contentLabel = [UILabel new];
    _contentLabel.translatesAutoresizingMaskIntoConstraints = NO;
    _contentLabel.numberOfLines = 0;
    _contentLabel.font = [UIFont fontWithName: @"Courier" size: 40];
    _contentLabel.text = self.loremIpsum;
    [_containerView addSubview: _contentLabel];

    // configure constraints for each view:

    [_scrollView mas_makeConstraints: ^(MASConstraintMaker *make) {

        // glue the scrollview to its superview with a 20 point inset:

        make.top.equalTo( self.view.mas_top ).with.offset( 20 );
        make.left.equalTo( self.view.mas_left ).with.offset( 20 );
        make.right.equalTo( self.view.mas_right ).with.offset( -20 );
        make.bottom.equalTo( self.view.mas_bottom ).with.offset( -20 );
    }];

    [_containerView mas_makeConstraints: ^(MASConstraintMaker *make) {

        // per the iOS 6.0 Release Notes, this is how to use auto-layout for a container view
        // inside a scrollview.  basically, tie the edges of the containerview to the scrollview.
        // http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/
        // see section "Here are some notes regarding Auto Layout support for UIScrollView"

        make.top.equalTo( _scrollView.mas_top );
        make.left.equalTo( _scrollView.mas_left );
        make.right.equalTo( _scrollView.mas_right );
        make.bottom.equalTo( _scrollView.mas_bottom );

        // match the width of the containerview to the scrollview width:
        make.width.equalTo( _scrollView.mas_width );

        // match the height of the containerview to the intrinsic height of the contentlabel + 100 points for our fixed height title

        // (this is the magical part.)
        make.height.equalTo( _contentLabel.mas_height ).with.offset( 100 );
    }];

    [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {

        // tie the contentlabel edges to the sides of its container:
        make.top.equalTo( _containerView.mas_top ).with.offset(0);
        make.left.equalTo( _containerView.mas_left ).with.offset(0);
        make.right.equalTo( _containerView.mas_right ).with.offset(0);

        // fixed height
        make.height.equalTo( @100 );
    }];

    [_contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {

        // tie top edge to the bottom of our title
        make.top.equalTo( _titleLabel.mas_bottom );

        // tie the remaining edges to the sides of the container:
        make.left.equalTo( _containerView.mas_left );
        make.right.equalTo( _containerView.mas_right );
        make.bottom.equalTo( _containerView.mas_bottom );
    }];
}

- (void) viewWillLayoutSubviews
{
    // perform a scrollview layout so the containerView width will be set
    [_scrollView setNeedsLayout];
    [_scrollView layoutIfNeeded];

    // update the preferred layout width of the content label;
    // this affects the label's intrinsicContentSize and will force our constraints to be recalculated
    CGFloat preferredWidth = _containerView.frame.size.width;
    _contentLabel.preferredMaxLayoutWidth = preferredWidth;


    // we don't need this since the scrollview is fully using autolayout to adjust the content-size.  but just to show that it works:

    CGSize fittingSize = [_containerView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];

    NSLog( @"container fitting size: %@", NSStringFromCGSize( fittingSize ));
}

- (NSString*) loremIpsum
{
    return @"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing <br>Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type<br> and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
}

@end

And, here's the output from systemLayoutSizeFittingSize when the constraints are all working nicely:

2013-08-05 15:01:16.309 testLabelConstraints[8265:c07] container fitting size: {721, 6868}
like image 74
TomSwift Avatar answered Nov 17 '22 16:11

TomSwift


If I understand you, the problem is getting view or views that dynamically size to scroll properly when they are subviews of a ScrollView. It this is it, I've had this problem and it can be solved without even having to worry about content size.

Here is a link to a tech note from Apple entitled "UIScrollView and Autolayout" here

http://developer.apple.com/library/ios/technotes/tn2154/_index.html

There is easy to follow source in the note which detail two approaches to solving this issue. Hope this helps, it really helped me.

Additionally, if you're trying to iterate through a collection of subviews inside your ScrollView, read this article and example, again, lucid explanation with code.

Apeth Programming IOS 6, Chapter 20. Scroll Views on line here:

http://www.apeth.com/iOSBook/ch20.html

like image 41
wm_j_ray Avatar answered Nov 17 '22 16:11

wm_j_ray