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

前端 未结 29 1161
醉梦人生
醉梦人生 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:31

    Accepted answer is a only useful for tables with a single section. For multi-section UITableView just make sure that your header inherits from UITableViewHeaderFooterView and you will be fine.

    As an alternative, just embed your current header in the contentView of a UITableViewHeaderFooterView. Exactly like UITableViewCell works.

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

    Extended this solution http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ for table footer view:

    @interface AutolayoutTableView : UITableView
    
    @end
    
    @implementation AutolayoutTableView
    
    - (void)layoutSubviews {
        [super layoutSubviews];
    
        // Dynamic sizing for the header view
        if (self.tableHeaderView) {
            CGFloat height = [self.tableHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
            CGRect headerFrame = self.tableHeaderView.frame;
    
            // If we don't have this check, viewDidLayoutSubviews() will get
            // repeatedly, causing the app to hang.
            if (height != headerFrame.size.height) {
                headerFrame.size.height = height;
                self.tableHeaderView.frame = headerFrame;
                self.tableHeaderView = self.tableHeaderView;
            }
    
            [self.tableHeaderView layoutIfNeeded];
        }
    
        // Dynamic sizing for the footer view
        if (self.tableFooterView) {
            CGFloat height = [self.tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
            CGRect footerFrame = self.tableFooterView.frame;
    
            // If we don't have this check, viewDidLayoutSubviews() will get
            // repeatedly, causing the app to hang.
            if (height != footerFrame.size.height) {
                footerFrame.size.height = height;
                self.tableFooterView.frame = footerFrame;
                self.tableFooterView = self.tableFooterView;
            }
    
            self.tableFooterView.transform = CGAffineTransformMakeTranslation(0, self.contentSize.height - footerFrame.size.height);
            [self.tableFooterView layoutIfNeeded];
        }
    }
    
    @end
    
    0 讨论(0)
  • 2020-11-28 20:32

    I know this is an old post but After going through all the SO posts regarding this and passing a whole afternoon playing with this, I finally came up with a clean and yet very simple solution

    First of all, My view hierarchy looks like this:

    1. Table View
      1. View tableHeaderView
        1. View with an outlet called headerView

    Now inside the View (No.3), I set up all the constraints as I would normally including the bottom space to container. This will make the container (i.e. 3.View i.e. headerView) to size itself based on it's subviews and their constraints.

    After that, I set the constraints between 3. View and 2. View to these:

    1. Top Space to container: 0
    2. Leading Space to container: 0
    3. Trailing Space to container: 0

    Notice that I omit intentionally the bottom space intentionally.

    Once all of this is done in the storyboard, everything that's left to do is paste those three lines of codes:

    if (self.headerView.frame.size.height != self.tableView.tableHeaderView.frame.size.height) {
        UIView *header = self.tableView.tableHeaderView;
        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = self.headerView.frame.size.height + frame.origin.y;
        header.frame = frame;
        self.tableView.tableHeaderView = header;
    }
    
    0 讨论(0)
  • 2020-11-28 20:33

    Code:

      extension UITableView {
    
              func sizeHeaderToFit(preferredWidth: CGFloat) {
                guard let headerView = self.tableHeaderView else {
                  return
                }
    
                headerView.translatesAutoresizingMaskIntoConstraints = false
                let layout = NSLayoutConstraint(
                  item: headerView,
                  attribute: .Width,
                  relatedBy: .Equal,
                  toItem: nil,
                  attribute:
                  .NotAnAttribute,
                  multiplier: 1,
                  constant: preferredWidth)
    
                headerView.addConstraint(layout)
    
                let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
                headerView.frame = CGRectMake(0, 0, preferredWidth, height)
    
                headerView.removeConstraint(layout)
                headerView.translatesAutoresizingMaskIntoConstraints = true
    
                self.tableHeaderView = headerView
              }
      }
    
    0 讨论(0)
  • 2020-11-28 20:35

    An old post. But a good post. Here's my 2 cents.

    Firstly, ensure that your header view has its constraints arranged so that it can support it's own intrinsic content size. Then do the following.

    //ViewDidLoad
    headerView.translatesAutoresizingMaskIntoConstraints = false
    headerView.configure(title: "Some Text A")
    
    //Somewhere else
    headerView.update(title: "Some Text B)
    
    private var widthConstrained = false
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if widthConstrained == false {
            widthConstrained = true
            tableView.addConstraint(NSLayoutConstraint(item: headerView, attribute: .width, relatedBy: .equal, toItem: tableView, attribute: .width, multiplier: 1, constant: 0))
            headerView.layoutIfNeeded()
            tableView.layoutIfNeeded()
        }
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: { (context) in
            self.headerView.layoutIfNeeded()
            self.tableView.layoutIfNeeded()
        }, completion: nil)
    }
    
    0 讨论(0)
  • 2020-11-28 20:36

    In my case method with systemLayoutSizeFittingSize for some reason did not work. What worked for me is a modification of solution posted by HotJard (he's original solution also did not work in my case on iOS 8). What I needed to do is in header view place a subview and pin it to left, right, top (do not pin to bottom). Put everything using autolayout in that subview and in code do this:

    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];
        [self resizeHeaderToFitSubview];
    }
    
    - (void)resizeHeaderToFitSubview
    {
        UIView *header = self.tableView.tableHeaderView;
        [header setNeedsLayout];
        [header layoutIfNeeded];
        CGFloat height = CGRectGetHeight(header.subviews.firstObject.bounds);
        header.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
        self.tableView.tableHeaderView = nil;
        self.tableView.tableHeaderView = header;
    }
    
    0 讨论(0)
提交回复
热议问题