简体   繁体   中英

How to do Auto Layout XIB being added programmatically?

I'm trying to add subview programmatically so people can horizontally scroll to another section. But it looks like the subview doesn't fit to SuperView and the content not showing

Here's my code from ViewController.m

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    for (int i = 0; i < 2; i++)
    {
        CGRect frame;
        frame.origin.x = self.scrollView.frame.size.width * i;
        frame.size = self.scrollView.frame.size;
        self.scrollView.pagingEnabled = YES;

        NewsSection *sectionView = [[NewsSection alloc] initWithFrame:frame];            

        [self.scrollView addSubview:sectionView];
    }

    self.scrollView.contentSize =  CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height);


}

This is my StoryBoard and constraints.

在此处输入图片说明

And this is my NewsSection.xib 在此处输入图片说明

This is my code of NewsSection.m

-(id) initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if(self) {
        [[NSBundle mainBundle] loadNibNamed:@"NewsSection" owner:self options:nil];

        [self addSubview:self.view];
    }
    return self;
}

And this is the result I'm seeing

在此处输入图片说明

UPDATE: Product code is here https://github.com/noppanit/UIScrollViewAutoLayout

I'll start off with a good read regarding UIScrollView and Autolayout: https://developer.apple.com/library/ios/technotes/tn2154/_index.html

Now, here's some sample code that should keep you get going. You just need to make your NewsView be managed by a ViewController, eg NewsViewController , and initialize NewsViewController before using it in setupNewsView :

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setupNewsView];
}

- (void) setupNewsView
{
     UIView *newsView = [[NewsSection alloc] initWithFrame:CGRectZero];

    self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    newsView.translatesAutoresizingMaskIntoConstraints = NO;

    [self.scrollView addSubview:newsView];

    NSDictionary *viewsDict = @{ @"newsView": newsView };

    [self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[newsView]|"
                                                                            options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom
                                                                            metrics:nil
                                                                              views:viewsDict]];
    [self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[newsView]|"
                                                                        options:0
                                                                        metrics:nil
                                                                          views:viewsDict]];

    [self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
                                                                attribute:NSLayoutAttributeWidth
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:self.scrollView
                                                                attribute:NSLayoutAttributeWidth
                                                               multiplier:1.0f
                                                                 constant:0.0f]];

    [self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
                                                                attribute:NSLayoutAttributeHeight
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:self.scrollView
                                                                attribute:NSLayoutAttributeHeight
                                                               multiplier:1.0f
                                                                 constant:0.0f]];
}

EDIT:

I'm sorry. I missed to add this line in my solution before:

[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[newsView]|"
                                                                        options:0
                                                                        metrics:nil
                                                                          views:viewsDict]];

Regarding your code sample: First, fill your ViewController exactly as my code sample depicts. I already incorporated the change into first sample. Also remove the code that overrides viewDidLayoutSubviews .

Then, you need to change the initializer of your NewsView .

Now it looks like this:

-(id) initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if(self) {
        [[NSBundle mainBundle] loadNibNamed:@"NewsSection" owner:self options:nil];

        [self addSubview:self.view];
    }
    return self;
}

One problem is here is that you load the nib but don't assign the view from the nib to your view object. The reference ( https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/NSBundle_UIKitAdditions/index.html ) depicts that loadNibNamed:owner:options: returns all top level objects. Since we have one top level object in our xib we need to assign this to ourself. This is somewhat hacky and introduces the problem that the nib will leak in the future. So better make a UIViewController with XIB here.

To make your code work, the initializer of NewsView should look like this. But it won't connect your outlet.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self = [[NSBundle mainBundle] loadNibNamed:@"NewsSection" owner:self options:nil][0];
    }
    return self;
}

It's a bit hard to tell what needs to be done from the outside.

Some things you will very likely need to do:

Set translatesAutoresizingMaskIntoConstraints on your view to NO so it doesn't create a whole new set of constraints that conflict with the constraints on your existing view hierarchy.

Add constraints to your newly added view in code that anchor it into your new view hierarchy. You have to add the constraints AFTER you add it as a subview. You will probably need to set a leading edge and a top constraint, and then either height and width or trailing and bottom constraints.

You'll probably want to use the method

+ constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM