简体   繁体   中英

Adding programatically created views into scrollview vertically (Linear layout in iOS)

I want to add programatically created UIViews into scrollView with auto layout constraints. Like vertical linear layout in Android. (In objective c not swift)

I have scrollview inside view controller in storyboard. So basically i want to create and add several views in vertical layout with no spaces into that scrollview. And i want to set container size of the scroll view dynamically according to the view heights.

Each view has label inside and each view needs to set its height dynamically according to text size. But probably i need to come to that later.

for (int i=0; i<10; i++)
{
    UIView *viewOne = UIView.new;
    [viewOne setTranslatesAutoresizingMaskIntoConstraints:NO];
    viewOne.backgroundColor = [UIColor redColor];
    NSDictionary *viewsDictionary = @{@"viewOne" : viewOne};
    NSDictionary *metricsDictionary = @{@"horizontalSpacing" : @10};

    [self.scrollview addSubview:viewOne];

    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-horizontalSpacing-[viewOne]-horizontalSpacing-|"
                                                                             options:NSLayoutFormatDirectionLeadingToTrailing
                                                                             metrics:metricsDictionary
                                                                               views:viewsDictionary];

    NSArray *const_Height = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[viewOne(50)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    [viewOne addConstraints:const_Height];
    [self.scrollview addConstraints:horizontalConstraints];
}

With that code i can add views but i need to add one under the other.

In case of using AutoLayout in the context of a UIScrollView I would recommend using a ContentView insider your UIScrollView. Just add them to the ViewControllers View inside the viewDidLoad function.

@interface YourViewController ()
@property (nonatomic, strong) UIScrollView *dataScrollView;
@property (nonatomic, strong) UIView* contentView;
@end

@implementation YourViewController
@synthesize dataScrollView, contentView;

- (void) viewDidLoad {
    [super viewDidLoad];

    dataScrollView  = [[UIScrollView alloc] init];
    contentView = [[UIView alloc] init];

    // adding the Views programmatically to the hierarchy
    [self.view addSubview:dataScrollView];
    [dataScrollView addSubview:contentView];

    // don't translate the AutoresizingMask into constraints
    dataScrollView.translatesAutoresizingMaskIntoConstraints  = NO;
    contentView.translatesAutoresizingMaskIntoConstraints = NO;

    // backgroundColor as you wish?
    dataScrollView.backgroundColor = [UIColor clearColor];
    contentView.backgroundColor = [UIColor clearColor];

    [dataScrollView setScrollEnabled:YES];
    [dataScrollView setAlwaysBounceVertical:YES];

    NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(dataScrollView, contentView);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[dataScrollView]|" options:0 metrics: 0 views:viewsDictionary]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[dataScrollView]|" options:0 metrics: 0 views:viewsDictionary]];
    [dataScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView(==dataScrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
    [dataScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics: 0 views:viewsDictionary]];

    // see below
    // [self setUpViews];
}

This Code will do the Trick for one single view. Add your required Views as Subview to the contentView and set the Constraints.

- (void) setUpViews {
    UILabel* testLabel = [[UILabel alloc] init];
    [testLabel setText:@"Lorem Ipsum"];
    testLabel.translatesAutoresizingMaskIntoConstraints = NO;
    [contentView addSubview: testLabel];

    // clean up your code with this metrics Dictionary
    NSDictionary *metrics = @{@"margintop": @40,
                          @"marginleft": @10,
                          @"marginright": @10,
                          @"marginbottom": @20}

    // the Views we want to layout with Constraints
    NSDictionary *viewsDictionary = @{
                                  @"contentView":contentView,
                                  @"dataScrollView":dataScrollView,
                                  @"testLabel": testLabel}

    // Horizontal (testlabel)
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-marginleft-[testLabel]-marginright-|" options:0 metrics: metrics views:viewsDictionary]];
    // Vertical
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-margintop-[testLabel]-marginbottom-|" options:0 metrics: metrics views:viewsDictionary]];
}

Referring to your question of adding multiple Views in a for-loop, there are a lot of possible ways. This could be the easiest solution with constraintsWithVisualFormat .

- (void) setUpViews {
    NSDictionary *metrics = @{@"margintop": @40,
                          @"marginleft": @10,
                          @"marginright": @10,
                          @"marginbottom": @20,
                          };
    // Alsways like to have contentView and DataScrollView here
    NSMutableDictionary* dictViews = [[NSMutableDictionary alloc] initWithDictionary:@{@"contentView":contentView,
                                                                                   @"dataScrollView":dataScrollView}];

    // Basic Leading-String for Vertical Constraints
    NSString* verticalConstraintsString = @"V:|-margintop-";
    for (NSUInteger index = 0; index < 10; index++) {
        // Do your Magic here & add your View
        UILabel* testLabel = [[UILabel alloc] init];
        [testLabel setText:@"Lorem Ipsum"];
        testLabel.translatesAutoresizingMaskIntoConstraints = NO;
        [contentView addSubview: testLabel];

        // Add to global Mutable Views-Dictionary dictViews
        [dictViews setObject:testLabel forKey:[NSString stringWithFormat:@"testLabel%lu", (unsigned long)index]];
        // add "[testlabel1]" to the vertical Constraints
        verticalConstraintsString = [NSString stringWithFormat:@"%@[testLabel%lu]-", verticalConstraintsString, (unsigned long)index];
        // Add Horizontal Constraints
        [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-marginleft-[testLabel%lu]-marginright-|", (unsigned long)index] options:0 metrics: metrics views:@{@"testLabel-%lu":testLabel}]];
    }

    // Trailing-String
    verticalConstraintsString = [NSString stringWithFormat:@"%@marginbottom-|", verticalConstraintsString];
    NSDictionary *viewsDictionary = [[NSDictionary alloc] initWithDictionary:dictViews];

    // finally adding the vertical Constraints
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalConstraintsString options:0 metrics: metrics views:viewsDictionary]];
}

I hope this will help you to get your Views right.

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