iOS Autolayout Vertically equal space to fill parent view

后端 未结 3 1985
梦毁少年i
梦毁少年i 2020-12-04 14:04

I have a view controller with 12 UITextFields.

It fits a 3.5\" display very well.

\"enter

相关标签:
3条回答
  • 2020-12-04 14:07

    Check out PureLayout. It's designed to be the simplest and most programmer-friendly API possible for creating Auto Layout constraints in code.

    In response to your specific question, PureLayout offers a two primary APIs for distributing views, one where the spacing between each view is fixed (view size varies as needed), and the other where the size of each view is fixed (spacing between views varies as needed). The latter will accomplish what you're looking for without the use of any "spacer views".

    // NSArray+PureLayout.h
    
    // ...
    
    /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
    - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                    alignedTo:(ALAttribute)alignment
                             withFixedSpacing:(CGFloat)spacing;
    
    /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
    - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                    alignedTo:(ALAttribute)alignment
                                withFixedSize:(CGFloat)size;
    
    // ...
    
    0 讨论(0)
  • 2020-12-04 14:17

    To do this with auto layout, you must create extra views to fill the spaces between the text fields.

    Recall that an auto layout constraint is basically the linear equation A = m * B + c. A is an attribute of one view (for example, the Y coordinate of viewA's bottom edge) and B is an attribute of another view (for example, the Y coordinate of viewB's top edge). m and c are constants. So, for example, to lay out viewA and viewB so that there are 30 points between the bottom of viewA and the top of viewB, we could create a constraint where m is 1 and c is -30.

    The problem you're having is that you want to use the same value for c across 13 different constraints, and you want auto layout to compute that c value for you. Auto layout simply can't do that. Not directly. Auto layout can only compute the attributes of views; it cannot compute the m and c constants.

    There is a way to make auto layout put the views where you want: reify the spaces between the text fields as additional (invisible) views. Here's an example with just 3 text fields:

    We'll create a constraint to pin each spacer's top edge to the bottom edge of the text field above it. We'll also create a constraint to pin each spacer's bottom edge to the top edge of the text field below it. And finally, we'll create a constraint to force each spacer to have the same height as the topmost spacer.

    We'll need a two instance variables to set things up: an array of the text fields (in order from top to bottom), and a reference to the topmost spacer view:

    @implementation ViewController {
        NSMutableArray *textFields;
        UIView *topSpacer;
    }
    

    We'll create the text fields and spacers in code since it's hard to show a xib in a stackoverflow answer. We kick things off in viewDidLoad:

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.translatesAutoresizingMaskIntoConstraints = NO;
        [self addTextFields];
        [self addSpacers];
    }
    

    Since we're going to use auto layout, we need to turn off translatesAutoresizingMaskIntoConstraints to prevent the system from creating extra constraints.

    We create each text field, give it some dummy text, and set up constraints for its horizontal position and size:

    - (void)addTextFields {
        textFields = [NSMutableArray array];
        for (int i = 0; i < 12; ++i) {
            [self addTextField];
        }
    }
    
    - (void)addTextField {
        UITextField *field = [[UITextField alloc] init];
        field.backgroundColor = [UIColor colorWithHue:0.8 saturation:0.1 brightness:0.9 alpha:1];
        field.translatesAutoresizingMaskIntoConstraints = NO;
        field.text = [field description];
        [self.view addSubview:field];
        [field setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
        [field setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[field]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(field)]];
        [textFields addObject:field];
    }
    

    We'll use a loop to create the spacers too, but we create the top and bottom spacers differently from the middle spacers, because we need to pin the top and bottom spacers to the superview:

    - (void)addSpacers {
        [self addTopSpacer];
        for (int i = 1, count = textFields.count; i < count; ++i) {
            [self addSpacerFromBottomOfView:textFields[i - 1]
                toTopOfView:textFields[i]];
        }
        [self addBottomSpacer];
    }
    

    Here's how we create the top spacer and set up its constraints. Its top edge is pinned to the superview and its bottom edge is pinned to the first (topmost) text field. We store the top spacer in the instance variable topSpacer so we can constrain the other spacers to have the same height as the top spacer.

    - (void)addTopSpacer {
        UIView *spacer = [self newSpacer];
        UITextField *field = textFields[0];
        [self.view addConstraints:[NSLayoutConstraint
            constraintsWithVisualFormat:@"V:|[spacer][field]" options:0 metrics:nil
            views:NSDictionaryOfVariableBindings(spacer, field)]];
        topSpacer = spacer;
    }
    

    Here's how we actually create a spacer view. It's just a hidden view. Since we don't care about its horizontal size or position, we just pin it to the left and right edges of the superview.

    - (UIView *)newSpacer {
        UIView *spacer = [[UIView alloc] init];
        spacer.hidden = YES; // Views participate in layout even when hidden.
        spacer.translatesAutoresizingMaskIntoConstraints = NO;
        [self.view addSubview:spacer];
        [self.view addConstraints:[NSLayoutConstraint
            constraintsWithVisualFormat:@"|[spacer]|" options:0 metrics:nil
            views:NSDictionaryOfVariableBindings(spacer)]];
        return spacer;
    }
    

    To create a “middle” spacer between two text views, we pin it to the bottom edge of the text field above and the top edge of the text field below. We also constrain its height to equal the height of the top spacer.

    - (void)addSpacerFromBottomOfView:(UIView *)overView toTopOfView:(UIView *)underView {
        UIView *spacer = [self newSpacer];
        [self.view addConstraints:[NSLayoutConstraint
            constraintsWithVisualFormat:@"V:[overView][spacer(==topSpacer)][underView]" options:0 metrics:nil
            views:NSDictionaryOfVariableBindings(spacer, overView, underView, topSpacer)]];
    }
    

    To create the bottom spacer, we pin it to the last text field and to the superview. We also constrain its height to equal the height of the top spacer.

    - (void)addBottomSpacer {
        UIView *spacer = [self newSpacer];
        UITextField *field = textFields.lastObject;
        [self.view addConstraints:[NSLayoutConstraint
            constraintsWithVisualFormat:@"V:[field][spacer(==topSpacer)]|" options:0 metrics:nil
            views:NSDictionaryOfVariableBindings(spacer, field, topSpacer)]];
    }
    

    If you do it right, you will get a result like this:

    You can find a complete example project in this github repository.

    0 讨论(0)
  • 2020-12-04 14:31

    see developer.apple' documentation, that is having nice description about the solution, https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html see the spacing and warping in that page, i think that is nice description, so no need to explain same thing over here

    EDIT

    Above link is now get disabled by apple, As from iOS 9, they have introduced Stackview, which is solution for all this.

    Previously in above link the answer was same as answer provided by @rob

    0 讨论(0)
提交回复
热议问题