UITableViewHeaderFooterView subclass with auto layout and section reloading won't work well together

后端 未结 11 1293
天涯浪人
天涯浪人 2020-12-30 23:04

I am trying to incorporate auto layout into my UITableViewHeaderFooterView subclass. The class is pretty basic, just two labels. This is the complete subclass:



        
相关标签:
11条回答
  • 2020-12-30 23:42

    Need to update contentView frame, and the warnings are gone. This maybe similar to Auto layout constraints issue on iOS7 in UITableViewCell

    public class MyHeaderview: UITableViewHeaderFooterView {
        // Add views to contentView
    
        public override func layoutSubviews() {
            super.layoutSubviews()
            contentView.frame = bounds
        }
    }
    
    0 讨论(0)
  • 2020-12-30 23:44

    So weird! Thanks for this @josh-bernfield, here is what I wrote for iOS 11.3:

    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            if newValue.width == 0 { return }
            super.frame = newValue
        }
    }
    
    0 讨论(0)
  • 2020-12-30 23:50

    I came upon this issue and the best solution I found is to set a default frame in the init. That frame will be changed anyway but it is useful for the constraints that would break on a 0,0,0,0 frame.

    override init(reuseIdentifier: String?) {
            super.init(reuseIdentifier: reuseIdentifier)        
            frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    
            //... setup constraints...
    }
    
    0 讨论(0)
  • 2020-12-30 23:51

    I had a similar problem, only one UILabel in the contentView, and I used Masonry:

    _titleLabel = ({
        UILabel *label = [MLBUIFactory labelWithType:MALabelTypeB];
        [self.contentView addSubview:label];
        [label mas_makeConstraints:^(MASConstraintMaker */make) {
            make.centerY.equalTo(self.contentView);
            make.left.equalTo(self.contentView).offset(8);
            make.right.equalTo(self.contentView).offset(-8);
        }];
    
        label;
    });
    

    then I got the warning:

    (
    "<MASLayoutConstraint:0x1742b2c60 UILabel:0x124557ee0.left == _UITableViewHeaderFooterContentView:0x12454c640.left + 8>",
    "<MASLayoutConstraint:0x1742b3080 UILabel:0x124557ee0.right == _UITableViewHeaderFooterContentView:0x12454c640.right - 8>",
    "<NSLayoutConstraint:0x174280780 _UITableViewHeaderFooterContentView:0x12454c640.width == 0>"
    )
    Will attempt to recover by breaking constraint 
    <MASLayoutConstraint:0x1742b3080 UILabel:0x124557ee0.right == _UITableViewHeaderFooterContentView:0x12454c640.right - 8>
    

    so I tried to set self.translatesAutoresizingMaskIntoConstraints = NO;, but it didn't works for me, so I focused on the warning message, and I'm confused, why the left constraint work but right, when I saw the _UITableViewHeaderFooterContentView:0x12454c640.width == 0, I figured out, maybe that's why the right constraint is the breaking constraint, then I changed code:

    _titleLabel = ({
        UILabel *label = [MLBUIFactory labelWithType:MALabelTypeB];
        [self.contentView addSubview:label];
        [label mas_makeConstraints:^(MASConstraintMaker */make) {
            make.centerY.equalTo(self.contentView);
            make.left.equalTo(self.contentView).offset(8);
            make.width.equalTo(@(SCREEN_WIDTH - 16));
        }];
    
        label;
    });
    

    I replaced the right constraint with width constraint, and the warning gone.

    There has other way to let the warning gone: self.contentView.translatesAutoresizingMaskIntoConstraints = NO;, BUT the label's frame is wrong.

    0 讨论(0)
  • 2020-12-30 23:53

    In iOS 11 I just could not get UITableViewHeaderFooterView to display correctly.

    The problem was that I was setting my constraints when the UITableViewHeaderFooterView thought it's bounds were empty so it would always cause conflicts.

    Here's the solution

    override func layoutSubviews() {
        super.layoutSubviews()
        guard bounds != CGRect.zero else {
            return
        }
        makeConstraints()
    }
    
    0 讨论(0)
  • 2020-12-30 23:53

    I think we can safely ignore the console warning.

    I suspect the console log is caused by some intermediate state of the table view layout process.

    When I add a footer section view with auto layout content, I get unsatisfiable constraints warning in the console as well.

    From the log below, the constraint causing problem should be _UITableViewHeaderFooterContentView:0x7ff2115778d0.height == 0

    2018-08-23 16:01:27.036159-0700 Attendee[45370:2760310] [LayoutConstraints] Unable to simultaneously satisfy constraints.
        Probably at least one of the constraints in the following list is one you don't want. 
        Try this: 
            (1) look at each constraint and try to figure out which you don't expect; 
            (2) find the code that added the unwanted constraint or constraints and fix it. 
    (
        "<NSLayoutConstraint:0x60000029d7e0 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.bottom == UIButton:0x7ff2115770a0.bottom + 20   (active)>",
        "<NSLayoutConstraint:0x604000481d60 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.top == UIButton:0x7ff211576790'Forgot password?'.top   (active)>",
        "<NSLayoutConstraint:0x604000481c70 UIButton:0x7ff211576790'Forgot password?'.bottom == UIButton:0x7ff2115770a0.top - 8   (active)>",
        "<NSLayoutConstraint:0x60000029d600 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide']-(8)-|   (active, names: '|':_UITableViewHeaderFooterContentView:0x7ff2115778d0 )>",
        "<NSLayoutConstraint:0x60000029da10 'UIView-Encapsulated-Layout-Height' _UITableViewHeaderFooterContentView:0x7ff2115778d0.height == 0   (active)>",
        "<NSLayoutConstraint:0x60000029d560 'UIView-topMargin-guide-constraint' V:|-(8)-[UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide']   (active, names: '|':_UITableViewHeaderFooterContentView:0x7ff2115778d0 )>"
    )
    
    Will attempt to recover by breaking constraint 
    <NSLayoutConstraint:0x60000029d7e0 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.bottom == UIButton:0x7ff2115770a0.bottom + 20   (active)>
    

    If I override layoutSubviews of the footer view to dump the constraints affecting vertical layout:

    override func layoutSubviews() {
        super.layoutSubviews()
    
        print("after layout")
        dump(contentView.constraintsAffectingLayout(for: .vertical))
    }
    

    I get the following output:

    ▿ 2 elements
      - <NSLayoutConstraint:0x600000297110 'UIView-Encapsulated-Layout-Height' _UITableViewHeaderFooterContentView:0x7ffc22d88c20.height == 101   (active)> #0
        - super: NSObject
      - <NSAutoresizingMaskLayoutConstraint:0x6000002971b0 h=--& v=--& 'UIView-Encapsulated-Layout-Top' _UITableViewHeaderFooterContentView:0x7ffc22d88c20.minY == 0   (active, names: '|':Attendee.SearchFormButtonFooter:0x7ffc22d20da0 )> #1
        - super: NSLayoutConstraint
          - super: NSObject
    

    There's no explicit layout constraint setting the height of the content view to 0. It's probably just the autosizing mask of content view causing the issue in some intermediate state of UITableView layout process.

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