iOS 7上的UITableView行删除动画闪烁

时间:2014-04-17 09:28:50

标签: ios ios7 uitableview

我的应用程序有一个UITableView,其中包含具有透明背景的可变高度单元格。在针对iOS 7 SDK构建时,行删除动画存在问题:

UITableView cell delete animation

注意一些细胞的闪烁,例如第15,17,21和23行。在iOS< = 6上未观察到此行为。

如果我做了这些事情中的任何一个问题就会消失(我还没准备好这样做):

  • 始终创建新单元格而不是使可重用单元格出列
  • 为细胞提供不透明的背景
  • 为所有行提供相同的高度

我尝试过的其他任何帮助。 iOS 7上是否需要一些秘密酱才能获得平滑的行删除动画?

这是我可以将问题提炼到[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;
    }
}

1 个答案:

答案 0 :(得分:3)

TLDR:cell.clipsToBounds = YES;

====

这是我发现的:

'   |    |    |    | <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>>

如果你仔细观察第27行,你会注意到单元格的高度是32px。单元格的子视图是一个scrollView(我读过的地方是你向左滑动以显示iOS7中的行动作的滚动视图)。正如我们所看到的,contentView具有32px的正确高度,但是,这里是有趣部分开始的地方:在contentView后面有一个视图,其高度为51像素。我相信这是罪魁祸首。

不幸的是,我无法找到哪个视图(它不是backgroundView,它不是selectedBackgroundView等,简而言之:它不是UITableViewCell类的公共属性中的任何视图)。 / p>

另外,在事物的可怕方面,该视图的backgroundColor是clearColor。理论上它甚至不应该是可见的!我相信,我们在这里处理的是一些CoreAnimation优化,它不会渲染这个神秘视图背后的区域。

那么,会发生什么:1)细胞被创建2)细胞被调整大小并准备呈现3)细胞获得正确大小的神秘视图4)细胞被重复使用5)细胞被调整为新的动态高度6)scrollView&amp; contentView也会调整大小,但神秘视图不是(请注意它没有设置任何调整大小的掩码)。

这解释了为什么您能够以上述三种方式解决此问题。

解决方法是在创建时设置单元格cell.clipsToBounds = YES;。 我还建议不要设置cell.backgroundColor。 IIRC,您应该使用cell.backgroundView(将其设置为新创建的视图并将其设置为backgroundColor)。然而,单元格的默认bacgroundColor无论如何都是清晰的,所以在这种情况下这并不重要。

我很高兴听到某人的私人观点是什么。