Resize UITableView Header AND containing UITextView (iOS7 + AutoLayout)

后端 未结 4 462
一个人的身影
一个人的身影 2020-12-25 08:37

I\'ve been struggling with this now for a little while, and I want to make sure I\'m doing this the right way. For reference, I am using AutoLayout with Storyboards, and it

4条回答
  •  离开以前
    2020-12-25 09:25

    Some time ago I found new solution, maybe it needs tweaking for animations and is experimental, but, for some range of cases it's fine, so give it a try:

    1. Add a headerView to a UITableView.
    2. Add a subview to headerView, let's call it wrapper.
    3. Make wrapper's height be adjusted with it's subviews (via Auto Layout).
    4. When autolayout had finished layout, set headerView's height to wrapper's height. (see -updateTableViewHeaderViewHeight)
    5. Re-set headerView. (see -resetTableViewHeaderView)

    Here's some code:

    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];
    
        [self updateTableViewHeaderViewHeight];
    }
    
    /**
     tableView's tableViewHeaderView contains wrapper view, which height is evaluated
     with Auto Layout. Here I use evaluated height and update tableView's
     tableViewHeaderView's frame.
    
     New height for tableViewHeaderView is applied not without magic, that's why 
     I call -resetTableViewHeaderView.
     And again, this doesn't work due to some internals of UITableView, 
     so -resetTableViewHeaderView call is scheduled in the main run loop.
    */
    - (void)updateTableViewHeaderViewHeight
    {
        // get height of the wrapper and apply it to a header
        CGRect Frame = self.tableView.tableHeaderView.frame;
        Frame.size.height = self.tableHeaderViewWrapper.frame.size.height;
        self.tableView.tableHeaderView.frame = Frame;
    
        // this magic applies the above changes
        // note, that if you won't schedule this call to the next run loop iteration
        // you'll get and error
        // so, I guess that's not a clean solution and could be wrapped in @try@catch block
        [self performSelector:@selector(resetTableViewHeaderView) withObject:self afterDelay:0];
    }
    
    // yeah, guess there's something special in the setter
    - (void)resetTableViewHeaderView
    {
        // whew, this could be animated!
        [UIView beginAnimations:@"tableHeaderView" context:nil];
    
            self.tableView.tableHeaderView = self.tableView.tableHeaderView;
    
        [UIView commitAnimations];
    }
    

    All this works seamlessly after the initial autolayout pass. Later, if you change wrapper's contents so that it gains different height, it wont work for some reason (guess laying out UILabel requires several autolayout passes or something). I solved this with scheduling setNeedsLayout for the ViewController's view in the next run loop iteration.

    I've created sample project for that: TableHeaderView+Autolayout.

提交回复
热议问题