How to animate UITableView header view

2019-02-09 01:55发布

I need to animate the insertion of a tableview header view. I want that the table rows to slide down while the header view expands its frame.
So far the best result I got is by using the following code:

[self.tableView beginUpdates];  
[self.tableView setTableHeaderView:self.someHeaderView];  
[self.tableView endUpdates];

The problem with this solution is that the header itself doesn't get animated, its frame doesn't expand.

So the effect I'm getting is that the table rows slide down (as I want) but the header view is immediately shown, and I want it to expand it's frame with animation.

Any ideas?

Thanks.

6条回答
男人必须洒脱
2楼-- · 2019-02-09 02:11

SWIFT 4 SOLUTION w/ Different Header

If you want this kind of animation, that is the solution that I have used: (even though in my case I had also to play a bit with the opacity of the objects, since I was loading another completely different header)

fileprivate func transitionExample() {

    let oldHeight = tableView.tableHeaderView?.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height ?? 0

    let newHeader = YourCustomHeaderView()
    newHeader.hideElements() // If you want to play with opacity.

    let smallHeaderFrame = CGRect(x: 0, y: 0, width: newHeader.frame.width, height: oldHeight)
    let fullHeaderFrame = newHeader.frame

    newHeader.frame = smallHeaderFrame

    UIView.animate(withDuration: 0.4) { [weak self] in
        self?.tableView.beginUpdates()
        newHeader.showElements() // Only if have hided the elements before.
        self?.tableView.tableHeaderView = newHeader
        self?.tableView.tableHeaderView?.frame = fullHeaderFrame
        self?.tableView.endUpdates()
    }
}

So, basically, it's all about changing the frame inside the .animate closure. The beging/end updates is needed in order to move and update the other elements of the tableView.

查看更多
Juvenile、少年°
3楼-- · 2019-02-09 02:12

have the header frame at CGRectZero and set its frame using animation

[self.tableView beginUpdates];  
[self.tableView setTableHeaderView:self.someHeaderView];  

[UIView animateWithDuration:.5f animations:^{
  CGRect theFrame = someBigger.frame;
  someHeaderView.frame = theFrame;
}];

[self.tableView endUpdates];  
查看更多
劫难
4楼-- · 2019-02-09 02:27

Here's what I got to work in Swift, with an initial frame height of zero and updating it to its full height in the animations closure:

// Calculate new frame size for the table header
var newFrame = tableView.tableHeaderView!.frame
newFrame.size.height = 42

// Get the reference to the header view
let tableHeaderView = tableView.tableHeaderView

// Animate the height change
UIView.animate(withDuration: 0.6) {
    tableHeaderView.frame = newFrame
    self.tableView.tableHeaderView = tableHeaderView
})
查看更多
戒情不戒烟
5楼-- · 2019-02-09 02:29

I found the definitive and proper way to achieve a real animation on tableHeaderViews!

• First, if you're in Autolayout, keep the Margin system inside your header view. With Xcode 8 its now possible (at last!), just do not set any constraint to any of the header subviews. You'll have to set the correct margins thought.

• Then use beginUpdates and endUpdates, but put endUpdate into the animation block.

// [self.tableView setTableHeaderView:headerView]; // not needed if already there
[self.tableView beginUpdates]; 
CGRect headerFrame = self.tableView.tableHeaderView.bounds;
headerFrame.size.height = PLAccountHeaderErrorHeight;

[UIView animateWithDuration:0.2 animations:^{
    self.tableView.tableHeaderView.bounds = headerFrame;

    [self.tableView endUpdates];
}];

Note: I only tried in iOS10, i'll post an update when my iOS9 simulator will be downloaded.

EDIT

Unfortunately, it doesn't work in iOS9 as well as iOS10: the header itself does not change its height, but header subviews seem to move as if the header bounds changed.

查看更多
聊天终结者
6楼-- · 2019-02-09 02:30

The selected answer didn't work for me. Had to do the following:

[UIView animateWithDuration: 0.5f
                 animations: ^{
                     CGRect frame = self.tableView.tableHeaderView.frame;
                     frame.size.height = self.headerViewController.preferredHeight;
                     self.tableView.tableHeaderView.frame = frame;
                     self.tableView.tableHeaderView = self.tableView.tableHeaderView;
                   }];

The really peculiar part is that this works in one view but not in a subclass of the same view controller / view hierarchy.

查看更多
Emotional °昔
7楼-- · 2019-02-09 02:33

Use below code this works

extension UITableView {

 func hideTableHeaderView() -> Void {
    self.beginUpdates()
    UIView.animate(withDuration: 0.2, animations: {
        self.tableHeaderView = nil
    })
    self.endUpdates()
}

func showTableHeaderView(header: UIView) -> Void {
    let headerView = header
    self.beginUpdates()
    let headerFrame = headerView.frame
    headerView.frame = CGRect()
    self.tableHeaderView = headerView
    UIView.animate(withDuration: 0.2, animations: {
        self.tableHeaderView?.frame = headerFrame
        self.tableHeaderView?.alpha = 0
        self.endUpdates()
    }, completion: { (ok) in
        self.tableHeaderView?.alpha = 1
    })
   }
}
查看更多
登录 后发表回答