UITableView row delete animation flickers on iOS 7

rodney

My app has a UITableView containing variable-height cells with transparent backgrounds. When building against the iOS 7 SDK there's a problem with the row deletion animation:

UITableView cell delete animation

Note the flickering of some cells, e.g. rows 15, 17, 21 and 23. This behavior was not observed on iOS <= 6.

If I do any of these things the problem goes away (none of which I'm yet prepared to do):

  • Always creating new cells instead of dequeueing reusable cells
  • Giving cells non-transparent backgrounds
  • Giving all rows the same height

Nothing else I've tried helps. Is there some secret sauce required on iOS 7 to get smooth row deletion animations?

Here's the smallest test case I can distill the problem to [C#/Xamarin]:

public class MainViewController : UITableViewController {

    public MainViewController() {
        this.TableView.Source = new TableSource(this.TableView, 50);
    }

    public override void ViewDidAppear(bool animated) {
        base.ViewDidAppear(animated);
        NSTimer.CreateRepeatingScheduledTimer(0.5f, ((TableSource) this.TableView.Source).DeleteFirstRow);
    }
}

public class TableSource : UITableViewSource {

    private UITableView tableView;
    private List<RowInfo> activeRows;

    public TableSource(UITableView tableView, int numRows) {

        this.tableView = tableView;

        this.activeRows = new List<RowInfo>();
        for (int i=1; i<=numRows; i++) {
            this.activeRows.Add(new RowInfo(i));
        }
    }

    public void DeleteFirstRow() {

        if (this.activeRows.Count == 0) return;

        this.activeRows.RemoveAt(0);

        this.tableView.BeginUpdates();
        this.tableView.DeleteRows(new NSIndexPath[] { NSIndexPath.FromRowSection(0, 0) }, UITableViewRowAnimation.Right);
        this.tableView.EndUpdates();
    }

    public override int RowsInSection(UITableView tableview, int section) {
        return this.activeRows.Count;
    }

    public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath) {
        return this.activeRows[indexPath.Row].Height;
    }

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) {

        const string CellID = "Cell";

        UITableViewCell cell = tableView.DequeueReusableCell(CellID);
        if (cell == null) {
            cell = new UITableViewCell(UITableViewCellStyle.Default, CellID);
        }
        cell.TextLabel.Text = this.activeRows[indexPath.Row].Text;

        return cell;
    }

    public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath) {
        cell.BackgroundColor = UIColor.Clear;
    }

    private class RowInfo {

        public RowInfo(int index) {
            Random random = new Random(index);
            this.Height = random.Next(20, 80);
            this.Text = "Row " + index + " has height " + this.Height;
        }

        public float Height;
        public string Text;
    }
}
user3099609

TLDR: cell.clipsToBounds = YES;

====

Here's what I found:

'   |    |    |    | <UITableViewCell: 0x79e81910; frame = (0 232; 320 32); text = 'row 27'; clipsToBounds = YES; autoresize = W; animations = { position=<CABasicAnimation: 0x79e8f020>; }; layer = <CALayer: 0x79e81aa0>>
   |    |    |    |    | <UITableViewCellScrollView: 0x79e81ad0; frame = (0 0; 320 32); autoresize = W+H; gestureRecognizers = <NSArray: 0x79e81d60>; layer = <CALayer: 0x79e81ca0>; contentOffset: {0, 0}>
   |    |    |    |    |    | <UIView: 0x79e8b7d0; frame = (0 0; 320 51); clipsToBounds = YES; layer = <CALayer: 0x79e8b830>>
   |    |    |    |    |    | <UITableViewCellContentView: 0x79e81f50; frame = (0 0; 320 31.5); gestureRecognizers = <NSArray: 0x79e82160>; layer = <CALayer: 0x79e81fc0>>
   |    |    |    |    |    |    | <UILabel: 0x79e821b0; frame = (15 0; 290 31.5); text = 'row 27'; userInteractionEnabled = NO; layer = <CALayer: 0x79e82260>>
   |    |    |    |    |    | <_UITableViewCellSeparatorView: 0x79e824d0; frame = (15 31.5; 305 0.5); layer = <CALayer: 0x79e82540>>

If you look closely at row 27, you'll notice that the cell's height is 32px. The subviews of the cell is a scrollView (I've read somewhere that's the scroll view that you swipe left to show the row actions in iOS7). The contentView, as we see, has the correct height of 32px, but, and here's where the funny part begins: there's a view just behind the contentView, that has a height of 51 px. I believe that's the culprit.

Unfortunately, I wasn't able to find which view is that (it's not the backgroundView, it's not the selectedBackgroundView, etc., in short: it's not any of the views in the public properties of the UITableViewCell class).

Also, on the wierd side of things, that view's backgroundColor is clearColor. In theory it shouldn't even be visible! What we're dealing here is, I believe, some CoreAnimation optimization that doesn't render the area behind this mystery view.

So, what happens is: 1) the cell is created 2) cell is resized and prepared to be presented 3) cell gets its mystery view added of the correct size 4) cell gets reused 5) cell is resized to the new dynamic height 6) scrollView & contentView get resized as well, but the mystery view isn't (please note it doesn't have any resize mask set).

This explains why you're able to fix this issue in any of the three described ways.

The workaround is to set the cell's cell.clipsToBounds = YES; upon creation. I would also recommend against setting the cell.backgroundColor. IIRC, you should use the cell.backgroundView for that (set it to a newly created view and set it's backgroundColor instead). However the cell's default bacgroundColor is clear anyway, so this doesn't really matter in this context.

I would be glad to hear from someone what's this private view for.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Weird UITableView insert/delete row animation

From Dev

iOS UITableView delete cells with animation one by one

From Dev

iOS - Delete row from UITableView crash

From Dev

iOS - Delete row from UITableView crash

From Dev

Delete the extra separator of UITableView in iOS 7

From Dev

How to delete rows from UITableView without animation in IOS

From Dev

iOS 7 UITableView didSelectRowAtIndexPath pushViewController programmatically, Animation issue

From Dev

How to remove gap before first row of UITableView in IOS 7

From Dev

problems with animation when deleting the last row of a TableView in ios7

From Dev

IOS inserting a row into UITableView

From Dev

UITableView Empty in iOS 7

From Dev

UITableView row delete crashes app

From Dev

Delete UITableView row from UITableViewCell?

From Dev

iOS 7 UINavigationController transition to UITableView: black-translucent layer during animation

From Dev

iOS 7 - Keyboard animation

From Dev

Android listview row delete animation

From Dev

uitableview delete button image in iOS

From Dev

Animation issue when deleting the last row of UITableView

From Dev

Animation issue when deleting the last row of UITableView

From Dev

Push row to top in UItableview in iOS

From Dev

Push row to top in UItableview in iOS

From Dev

iOS delete a tableview row

From Dev

iOS 7 UITableView issue - attempting to set a swipe to delete cell when we already have one

From Dev

In iOS 8.1, when I click on a row's delete button while UITableView is in edit mode, the row and those above it display incorrectly

From Java

UITableView is starting with an offset in iOS 7

From Dev

Multiple PickerView in UITableView on iOS 7

From Dev

Grouped UITableView glitch on iOS 7

From Dev

UITableView backgroundView gestures on iOS 7?

From Dev

Populating UITableView with NSArray in iOS 7

Related Related

  1. 1

    Weird UITableView insert/delete row animation

  2. 2

    iOS UITableView delete cells with animation one by one

  3. 3

    iOS - Delete row from UITableView crash

  4. 4

    iOS - Delete row from UITableView crash

  5. 5

    Delete the extra separator of UITableView in iOS 7

  6. 6

    How to delete rows from UITableView without animation in IOS

  7. 7

    iOS 7 UITableView didSelectRowAtIndexPath pushViewController programmatically, Animation issue

  8. 8

    How to remove gap before first row of UITableView in IOS 7

  9. 9

    problems with animation when deleting the last row of a TableView in ios7

  10. 10

    IOS inserting a row into UITableView

  11. 11

    UITableView Empty in iOS 7

  12. 12

    UITableView row delete crashes app

  13. 13

    Delete UITableView row from UITableViewCell?

  14. 14

    iOS 7 UINavigationController transition to UITableView: black-translucent layer during animation

  15. 15

    iOS 7 - Keyboard animation

  16. 16

    Android listview row delete animation

  17. 17

    uitableview delete button image in iOS

  18. 18

    Animation issue when deleting the last row of UITableView

  19. 19

    Animation issue when deleting the last row of UITableView

  20. 20

    Push row to top in UItableview in iOS

  21. 21

    Push row to top in UItableview in iOS

  22. 22

    iOS delete a tableview row

  23. 23

    iOS 7 UITableView issue - attempting to set a swipe to delete cell when we already have one

  24. 24

    In iOS 8.1, when I click on a row's delete button while UITableView is in edit mode, the row and those above it display incorrectly

  25. 25

    UITableView is starting with an offset in iOS 7

  26. 26

    Multiple PickerView in UITableView on iOS 7

  27. 27

    Grouped UITableView glitch on iOS 7

  28. 28

    UITableView backgroundView gestures on iOS 7?

  29. 29

    Populating UITableView with NSArray in iOS 7

HotTag

Archive