When you insert your first UITableViewCell
with insertRowsAtIndexPaths:withRowAnimation:
, it usually appears at the top of the UITableView
. In the Periscope app, the opposite happens - the first inserted cell is bottom aligned. As new cells are pushed in, the old cells move up in the table. How is this achieved?

- 3,714
- 6
- 41
- 67
-
1) Are you certain this is a `UITableView` with `UITableViewCell`s? 2) Assuming they are, are you certain the *top* of the `UITableView` in the first screenshot is the same place as the *top* of the `UITableView` in the second screenshot? – nhgrif May 02 '15 at 00:38
-
@nhgrif I am not certain how they've implemented it. I know how this effect can be achieved by not using tables at all, but using the standard table framework would be ideal because it handles cell memory management and animations for you. As for the frame.origin.y being the the same in the two photos, It would be hard to coordinate sliding the whole table up while new cells are being injected because the animation duration and curve of cell injection are not publicly accessible. – Pwner May 02 '15 at 00:46
-
I didn't say it'd be easy. – nhgrif May 02 '15 at 00:48
-
1I wonder if it could be done by starting with enough empty cells to fill the screen, and keeping the table view scrolled to the bottom when adding the new cell. What animation do you see when the cell is added? – rdelmar May 02 '15 at 02:27
-
@rdlmar That's a good idea. Just put a big blank cell on the top. The animation effect can be seen on [their website](https://www.periscope.tv/) (they have a video demo). – Pwner May 02 '15 at 07:10
-
@Pwner, I am stuck at fade out animation. Can you please share some idea? – Sushil Sharma Feb 05 '16 at 05:02
-
Can you say to me if you use 2 arrays for fill this tableView? One for the comments and the other one for the members just joined. Could you share your code about how you fill your tableViewCell with 2 customs cells. I want to do the same thing – Ghiggz Pikkoro Feb 05 '18 at 15:09
5 Answers
In case you're interested in how I did it in the Periscope iOS app, it's actually pretty simple...
TL;DR; Add a transparent table header header view with a height equal to your table view frame's height. Then, as you add cells to your table, simply animate the table view's content offset.
Give your table view a header view:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectZero];
headerView.userInteractionEnabled = NO; // all touches within this space must go through to the video layer
return headerView; // empty header above chat, so messages flow in from bottom
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return self.tableView.frame.size.height; // empty header above chat, so messages flow in from bottom
}
Add data to your table (in my case, messages get added to an array called _messages. I then call reloadData on the UITableViewController). Then call this method to animate the cells in:
- (void)scrollTableToBottom
{
if (!self.isViewLoaded || _messages.count == 0)
return;
CGFloat offsetY = self.tableView.contentSize.height - self.tableView.frame.size.height + self.tableView.contentInset.bottom;
[UIView animateWithDuration:0.33
delay:0
options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
[self.tableView setContentOffset:CGPointMake(0, offsetY) animated:NO];
}
completion:nil];
}
Hope that helps. I found this to be a pretty cheap/simple way of simulating cells anchored to the bottom. I know some people have mentioned flipping the table upside down, but that just seems crazy to me. :-)

- 1,249
- 11
- 8
-
Hello @Aaron Wasserman , Thanks for posting your code. Can you please suggest some method for fade out animation? I've tried many solution, couldn't get required result. – Sushil Sharma Feb 04 '16 at 12:15
-
Each of my cells has a view model that keeps track of the time it came on the screen and the time it started fading out. Then once a cell is reused and its new view model is set, you calculate where to start the animation from. The trick is to use CAAnimations which can easily be applied or removed from the layer. – Aaron Wasserman Apr 23 '16 at 17:20
-
-
1@AaronWasserman, I transform tableview and tableview cell with 180deg. tableView.transform = CGAffineTransformMakeRotation(-M_PI); cell.transform = CGAffineTransformMakeRotation(M_PI); I try to deleterowatindexpaths but it will not looks good like periscope so can you guild me like how can I remove old comments with fadeout effect? – Kuldeep May 11 '17 at 07:28
-
@AaronWasserman thanks for posting this. I'm having some strange scroll behavior when using autosizing cells. Can you please shed some light on how you configured it to handle dynamic height cells? Thanks. – Jorge Sep 11 '17 at 03:15
-
Problem I'm having with this is that now I have a large empty scroll area at the top of the table that I can scroll into, might be nice to clarify that in the answer as it might not be desired behaviour for everyone – Filip Kilibarda Jun 27 '23 at 03:34
Swift 4 version of Aaron Wasserman answer.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: .zero)
headerView.isUserInteractionEnabled = false
return headerView
}
// Added logic to avoid blank space at the top
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return tableView.frame.size.height - CGFloat(messages.count * cellHeight)
}
func scrollToBottom(animated: Bool) {
if isViewLoaded && messages.count > 0 {
let offset = tableView.contentSize.height - tableView.frame.size.height + tableView.contentInset.bottom
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut, .allowUserInteraction], animations: {
self.tableView.setContentOffset(CGPoint(x: 0, y: offset), animated: animated)
}, completion: nil)
}
}
scrollToBottom method needs to be called after tableView.reloadData()

- 93
- 3
My modification of the mr.Wasserman answer
extension MyViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: .zero)
headerView.isUserInteractionEnabled = false
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let diff = tableView.contentSize.height - tableView.bounds.height
return diff > 0 ? 0 : -diff
}
}

- 82
- 6
Bit late to the party, but here's another approach. It can be done without having to add arbitrary header views. Adjust the content offset whenever the content size changes.
class BottomEndianTableView: UITableView {
private var observer: Any?
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
observer = observe(\.contentSize) { _, _ in
DispatchQueue.main.async { [weak self] in
self?.scrollToEnd(animated: false)
}
}
}
func scrollToEnd(animated: Bool) {
let scrollDistance = contentSize.height - frame.height
setContentOffset(CGPoint(x: 0, y: scrollDistance), animated: animated)
}
}
You can also call scrollToEnd(animated: true)
in response to the keyboard displaying

- 3,193
- 24
- 29
You can use the insertRowsAtIndexPath method, and then get the tableview to scroll to bottom.
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.posts.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
If you wish to have that giant gap at the top of your tableview you can set the scroll offset, and adjust this as new items come in.
Another way, would be to flip the tableview upside down, and then flip each row upside down.

- 6,962
- 3
- 39
- 54