How to animate UITableView header view
Asked Answered
D

8

15

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.

Debauchee answered 13/5, 2013 at 9:19 Comment(2)
try #2659928Sanasanabria
Somthings should be easier : #49777606Battology
I
27

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];  
Iila answered 13/5, 2013 at 9:26 Comment(6)
Doesn't work, it looks like if you set the table's header with a view with height zero, then no matter if you latter change this view height, the table's header wont change..Debauchee
then try and increase the height for the TableHeaderView in the animation instead of the someHeaderView frameIila
The beginUpdates and endUpdates calls are not required.Sidon
If you want to move the tableView rows and footer as well (and you almost certainly do), you can trigger this with either begin/endUpdates or by re-setting tableView.tableViewHeader = tableView.tableViewHeader (not just the frame).Promulgate
@AndreasLey The beginUpdates and endUpdates calls are not necessarily required, but they ensure that rows aren't hidden before the animation finishesDingess
For me, it only works if I include the beginUpdates and endUpdates calls. iOS 9Ency
M
18

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
})
Missile answered 26/8, 2015 at 13:56 Comment(2)
This works for me. In order for the header size and the tableCell moving animations to sync up, I had to use an animationDuration of 0.3. On iOS 9 that is.Barquisimeto
Reassigning the tableHeaderView in the animation block worked for me as well. This should be the accepted answer.Smoulder
R
7

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.

Rosariorosarium answered 9/8, 2015 at 18:8 Comment(3)
Why is self.tableView.tableHeaderView = self.tableView.tableHeaderView; required? It doesn't work without this seemingly redundant line.Hemmer
@Hemmer Agreed that it is redundant but reseting the frame was required for it work for me.Rosariorosarium
@Hemmer I saw the same thing, I have to re-set the tableHeaderView to get the tableView to notice the new size. They probably do something in the didSet, seeing as it's a class reference, not a struct, so just a pointer is to an identical location. #16519080Promulgate
C
1

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.

Cowpox answered 16/9, 2016 at 14:38 Comment(0)
M
1

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.

Monachism answered 24/7, 2018 at 7:33 Comment(0)
O
1

Here is a Swift 5 UITableView extension for changing the headerView or changing its height, animated using AutoLayout

extension UITableView {

func animateTableHeader(view: UIView? = nil, frame: CGRect? = nil) {
    self.tableHeaderView?.setNeedsUpdateConstraints()
    UIView.animate(withDuration: 0.2, animations: {() -> Void in
        let hView = view ?? self.tableHeaderView
        if frame != nil {
            hView?.frame = frame!
        }
        self.tableHeaderView = hView
        self.tableHeaderView?.layoutIfNeeded()
    }, completion: nil)
}

}

Orenorenburg answered 25/7, 2019 at 22:31 Comment(0)
E
1

For me it is animated when using Auto Layout without any explicit animation block or manipulating frames.

// `tableHeaderViewHeight` is a reference to the height constraint of `tableHeaderView`
tableHeaderViewHeight?.constant = .leastNormalMagnitude

tableView.beginUpdates()
tableView.tableHeaderView = tableHeaderView
tableHeaderView.layoutIfNeeded()
tableView.endUpdates()
Endocrinology answered 2/3, 2022 at 15:33 Comment(0)
R
-1

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
    })
   }
}
Rosas answered 10/10, 2017 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.