Is it possible to use AutoLayout with UITableView's tableHeaderView?

前端 未结 29 1173
醉梦人生
醉梦人生 2020-11-28 19:51

Since I discovered AutoLayout I use it everywhere, now I\'m trying to use it with a tableHeaderView.

I made a subclass of

相关标签:
29条回答
  • 2020-11-28 20:41

    I encountered the problem of getting width 375pt, the only way that worked for me is to relayout the tableView to get the correct width. I also preferred AutoLayout over setting Frame size.

    Here's the version that works for me:

    Xamarin.iOS

    public static void AutoLayoutTableHeaderView(this UITableView tableView, UIView header)
    {
        tableView.TableHeaderView = header;
        tableView.SetNeedsLayout();
        tableView.LayoutIfNeeded();
        header.WidthAnchor.ConstraintEqualTo(tableView.Bounds.Width).Active = true;       
        tableView.TableHeaderView = header;
    }
    

    Swift Version (modified from @Ben Packard answer)

    extension UITableView {
        //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
        func setAndLayoutTableHeaderView(header: UIView) {
            self.tableHeaderView = header
            self.setNeedsLayout()
            self.layoutIfNeeded()
            header.widthAnchor.widthAnchor.constraint(equalTo: self.bounds.width).isActive = true
            self.tableHeaderView = header
        }
    }
    
    0 讨论(0)
  • 2020-11-28 20:42

    My solution is making a new class like this.

    class BaseTableHeaderView: UIView {
    
        func sizeToFitBasedOnConstraints(width: CGFloat = Screen.width) {
            let size = systemLayoutSizeFitting(CGSize(width: width, height: 10000),
                                                  withHorizontalFittingPriority: .required,
                                                  verticalFittingPriority: .fittingSizeLevel)
            frame = CGRect(origin: .zero, size: size)
        }
    
        override func willMove(toSuperview newSuperview: UIView?) {
            sizeToFitBasedOnConstraints()
            super.willMove(toSuperview: newSuperview)
        }
    
    }
    

    To use it, simply add all your subviews onto an instance of BaseTableHeaderView and attach it to your table view.

    let tableHeaderView = BaseTableHeaderView()
    tableHeaderView.addSubview(...)
    tableView.tableHeaderView = tableHeaderView
    

    It will automatically resize based on its constraints.

    0 讨论(0)
  • 2020-11-28 20:43

    I've been unable to add a header view using constraints (in code). If I give my view a width and/or a height constraint, I get a crash with the message saying:

     "terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."
    

    When I add a view in the storyboard to my table view, it shows no constraints, and it works fine as a header view, so I think that the placement of the header view isn't done using constraints. It doesn't seem to behave like a normal view in that regard.

    The width is automatically the width of the table view, the only thing you need to set is the height -- the origin values are ignored, so it doesn't matter what you put in for those. For instance, this worked fine (as does 0,0,0,80 for the rect):

    UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
    headerview.backgroundColor = [UIColor yellowColor];
    self.tableView.tableHeaderView = headerview;
    
    0 讨论(0)
  • 2020-11-28 20:44

    Strange things happens. systemLayoutSizeFittingSize works great for iOS9, but doesn't for iOS 8 in my case. So this problems solves quite easy. Just get link to the bottom view in header and in viewDidLayoutSubviews after super call update header view bounds by inserting height as CGRectGetMaxY(yourview.frame) + padding

    UPD: The easiest solution ever: So, in header view place subview and pin it to left, right, top. In that subview place your subviews with auto-height constraints. After that give all the job to the autolayout (no calculation required)

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        CGFloat height = CGRectGetMaxY(self.tableView.tableHeaderView.subviews.firstObject.frame);
        self.tableView.tableHeaderView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
        self.tableView.tableHeaderView = self.tableView.tableHeaderView;
    }
    

    As a result subview is expanding/shrinking like it should, at the end it calls viewDidLayoutSubviews. At the time we know the actual size of the view, so set headerView height and update it by re-assigning. Works like a charm!

    Also works for footer view.

    0 讨论(0)
  • 2020-11-28 20:44

    you can add top + horizontal location constraint between header and tableview, to place it, correctly (if the header itself contains all the necessary internal layout constraints to have a correct frame)

    in the tableViewController viewDidLoad method

        headerView.translatesAutoresizingMaskIntoConstraints = false
    
        tableView.tableHeaderView = headerView
    
        headerView.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
        headerView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
        headerView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true
    
    0 讨论(0)
提交回复
热议问题