Building a titleView programmatically with constraints (or generally constructing a view with constraints)

后端 未结 6 1797
长情又很酷
长情又很酷 2021-02-03 20:44

I\'m trying to build a titleView with constraints that looks like this:

\"titleView\"

I know how I would do

6条回答
  •  迷失自我
    2021-02-03 21:29

    an0's answer is correct. However, it doesn't help you getting the desired effect.

    Here's my recipe for building title views that automatically have the right size:

    • Create a UIView subclass, for instance CustomTitleView that will be later used as the navigationItem's titleView.
    • Use auto layout inside CustomTitleView. If you want to have your CustomTitleView being always centered, you'll need to add an explicit CenterX constraint (see code and link below).
    • Call updateCustomTitleView (see below) every time your titleView content updates. We need to set the titleView to nil and set it afterwards to our view again to prevent the title view being offset centered. This would happen when the title view changes from wide to narrow.
    • DON'T disable translatesAutoresizingMaskIntoConstraints

    Gist: https://gist.github.com/bhr/78758bd0bd4549f1cd1c

    Updating CustomTitleView from your ViewController:

    - (void)updateCustomTitleView
    {
        //we need to set the title view to nil and get always the right frame
        self.navigationItem.titleView = nil;
    
        //update properties of your custom title view, e.g. titleLabel
        self.navTitleView.titleLabel.text = <#my_property#>;
    
        CGSize size = [self.navTitleView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
        self.navTitleView.frame = CGRectMake(0.f, 0.f, size.width, size.height);
    
        self.navigationItem.titleView = self.customTitleView;
    }
    

    Sample CustomTitleView.h with one label and two buttons

    #import 
    
    @interface BHRCustomTitleView : UIView
    
    @property (nonatomic, strong, readonly) UILabel *titleLabel;
    @property (nonatomic, strong, readonly) UIButton *previousButton;
    @property (nonatomic, strong, readonly) UIButton *nextButton;
    
    @end
    

    Sample CustomTitleView.m:

    #import "BHRCustomTitleView.h"
    
    @interface BHRCustomTitleView ()
    
    @property (nonatomic, strong) UILabel *titleLabel;
    @property (nonatomic, strong) UIButton *previousButton;
    @property (nonatomic, strong) UIButton *nextButton;
    
    @property (nonatomic, copy) NSArray *constraints;
    
    @end
    
    @implementation BHRCustomTitleView
    
    - (void)updateConstraints
    {
        if (self.constraints) {
            [self removeConstraints:self.constraints];
        }
    
        NSDictionary *viewsDict = @{ @"title": self.titleLabel,
                                     @"previous": self.previousButton,
                                     @"next": self.nextButton };
        NSMutableArray *constraints = [NSMutableArray array];
    
        [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[previous]-2-[title]-2-[next]-(>=0)-|"
                                                                                 options:NSLayoutFormatAlignAllBaseline
                                                                                 metrics:nil
                                                                                   views:viewsDict]];
    
        [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[previous]|"
                                                                                 options:0
                                                                                 metrics:nil
                                                                                   views:viewsDict]];
    
        [constraints addObject:[NSLayoutConstraint constraintWithItem:self
                                                            attribute:NSLayoutAttributeCenterX
                                                            relatedBy:NSLayoutRelationEqual
                                                               toItem:self.titleLabel
                                                            attribute:NSLayoutAttributeCenterX
                                                           multiplier:1.f
                                                             constant:0.f]];
        self.constraints = constraints;
        [self addConstraints:self.constraints];
    
        [super updateConstraints];
    }
    
    - (UILabel *)titleLabel
    {
        if (!_titleLabel)
        {
            _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
            _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
            _titleLabel.font = [UIFont boldSystemFontOfSize:_titleLabel.font.pointSize];
    
            [self addSubview:_titleLabel];
        }
    
        return _titleLabel;
    }
    
    
    - (UIButton *)previousButton
    {
        if (!_previousButton)
        {
            _previousButton = [UIButton buttonWithType:UIButtonTypeSystem];
            _previousButton.translatesAutoresizingMaskIntoConstraints = NO;
            [self addSubview:_previousButton];
    
            _previousButton.titleLabel.font = [UIFont systemFontOfSize:23.f];
            [_previousButton setTitle:@"❮"
                             forState:UIControlStateNormal];
        }
    
        return _previousButton;
    }
    
    - (UIButton *)nextButton
    {
        if (!_nextButton)
        {
            _nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
            _nextButton.translatesAutoresizingMaskIntoConstraints = NO;
            [self addSubview:_nextButton];
            _nextButton.titleLabel.font = [UIFont systemFontOfSize:23.f];
            [_nextButton setTitle:@"❯"
                         forState:UIControlStateNormal];
        }
    
        return _nextButton;
    }
    
    + (BOOL)requiresConstraintBasedLayout
    {
        return YES;
    }
    
    @end
    

提交回复
热议问题