ios - iOS 7上UITableView行删除动画闪烁

标签 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;
    }
}

最佳答案

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 行,您会发现单元格的高度为 32 像素。单元格的 subview 是一个scrollView(我在某处读过,这是在iOS7中向左滑动以显示行操作的 ScrollView )。正如我们所看到的,contentView 的正确高度为 32px,但是,有趣的部分开始了:contentView 后面有一个 View ,其高度为 51px。我相信这就是罪魁祸首。

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

此外,奇怪的是,该 View 的背景颜色是clearColor。理论上它甚至不应该是可见的!我相信,我们在这里处理的是一些 CoreAnimation 优化,它不会渲染这个神秘 View 后面的区域。

因此,发生的情况是:1) 创建单元格 2) 调整单元格大小并准备好呈现 3) 单元格获得添加了正确大小的神秘 View 4) 单元格被重用 5) 单元格大小调整为新大小动态高度 6)scrollView 和 contentView 也会调整大小,但神秘 View 不会(请注意,它没有设置任何调整大小掩码)。

这解释了为什么您能够通过所描述的三种方法中的任何一种来解决此问题。

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

我很高兴收到某人的来信,这个私有(private) View 的用途是什么。

关于ios - iOS 7上UITableView行删除动画闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23129379/

相关文章:

ios7 - 不能在单点触控上覆盖 GetRendererForOverlay

ios - 是否有适用于 iOS 的可自定义 Cocoa 控件看起来像 Readdle 的日历 iPad 应用程序中的日期/时间选择器?

ios - 在隐藏对象之前等待动画完成

ios - Objective-C 中的属性

ios - 在展开可选内容时,将 Parse PFUser 信息快速加载到 View 中失败,并发现 nil

ios - UIGraphics 在 iOS 7 上崩溃

ios - UITableViewAutomaticDimension

Swift:从 Firebase 数据库检索数据以进行标签

iphone - 单击 UIToolBarButton 选中和取消选中 UITableViewCells

android - iphone 和 android 上的磁盘访问写入/更新数据的速度有多快