Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to center some images using iOS autolayout

I am doing this and I am curious whether it is the best way, or a dumb way!

I have a bunch of 40 pixel wide images, each one is like a Scrabble tile. My app wants to display some and center them on the screen. Only it don't know how many there are going to be! Could be between 3 and 10.

So I think best thing is if I count how many, multiple by 40, so I know how many pixels wide the whole thing will be, and then let's pretend it's 280 pixels - I will create a 280 px wide UIView, stick all the tiles in there, and then use Autolayout to center that UIView on the device.

That way if user rotates device, no problem!

Is this the best way? Also I am going to need to let the user drag the tiles out of that UIView and into another place on screen. Will that be possible?

like image 957
Cocorico Avatar asked Oct 04 '22 02:10

Cocorico


1 Answers

Three approaches leap out at me:

  1. I think your solution of using a container view is perfectly fine. But, you don't have to mess around with determining the size of the images. You can just define the relation between the container and the image views, and it will resize the container to conform to the intrinsic size of the image views (or if you explicitly define the size of the image views, that's fine, too). And you can then center the container (and not give it any explicit width/height constraints):

    // create container
    
    UIView *containerView = [[UIView alloc] init];
    containerView.backgroundColor = [UIColor clearColor];
    containerView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:containerView];
    
    // create image views
    
    UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.png"]];
    imageView1.translatesAutoresizingMaskIntoConstraints = NO;
    [containerView addSubview:imageView1];
    
    UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"2.png"]];
    imageView2.translatesAutoresizingMaskIntoConstraints = NO;
    [containerView addSubview:imageView2];
    
    NSDictionary *views = NSDictionaryOfVariableBindings(containerView, imageView1, imageView2);
    
    // define the container in relation to the two image views 
    
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView1]-[imageView2]|" options:0 metrics:nil views:views]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[imageView1]-|" options:0 metrics:nil views:views]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[imageView2]-|" options:0 metrics:nil views:views]];
    
    // center the container
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:containerView.superview
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1.0
                                                           constant:0]];
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:containerView.superview
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1.0
                                                           constant:0]];
    
  2. Another common solution with constraints is to create two extra UIView objects (sometimes called "spacer views"), for which you'll specify a background color of [UIColor clearColor], and put them on the left and right of your image views, and define them to go to the margins of the superview, and define the right view to be the same width of the left view. While I'm sure you're building your constraints as you're going along, if we were going to write the visual format language (VFL) for two imageviews to be centered on the screen, it might look like:

    @"H:|[leftView][imageView1]-[imageView2][rightView(==leftView)]|"
    
  3. Alternatively, you could eliminate the need for the container view or the two spacer views on the left and right by creating NSLayoutAttributeCenterX constraints using constraintWithItem, and specifying multiplier for the various image views so that they're spaced the way you want. While this technique eliminates the need for these two spacer views, I also think it's a little less intuitive.

    But it might look like:

    [imageViewArray enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:NSLayoutAttributeCenterX
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:view.superview
                                                                      attribute:NSLayoutAttributeCenterX
                                                                     multiplier:2.0 * (idx + 1) / ([imageViewArray count] + 1)
                                                                       constant:0];
        [view.superview addConstraint:constraint];
    }];
    

    This admittedly employs a slightly different spacing of the image views, but in some scenarios it's fine.

Personally, I'd lean towards the first approach, but any of these work.

like image 174
Rob Avatar answered Oct 07 '22 03:10

Rob