【问题标题】:Animating custom-drawn UITableViewCell when entering edit mode进入编辑模式时动画自定义绘制的 UITableViewCell
【发布时间】:2010-10-19 01:47:16
【问题描述】:

背景

首先,非常感谢atebits 提供了非常丰富的博文Fast Scrolling in Tweetie with UITableView。这篇文章详细解释了开发人员如何能够从Tweetie 中的 UITableViews 中挤出尽可能多的滚动性能。

目标

从博文 (original) (my github repo) 链接的源代码开始:

  1. 允许使用这些自定义单元格的 UITableView 切换到编辑模式,公开 UI 以从表格中删除项目。 (github commit)

  2. 当删除控件从左侧滑入时,将单元格的文本移到一边。这样就完成了,虽然文本在没有动画的情况下来回跳转。 (github commit)

  3. 将动画应用于上述目标 2 中的文本移动,以获得流畅的用户体验。这是我卡住的一步。

问题

介绍此动画以完成目标 3 的最佳方式是什么?如果可以以一种使逻辑与我的last commit 保持一致的方式来完成,那就太好了,因为我希望选择仅移动视图的冲突部分,而任何非冲突部分(例如右对齐文本) ) 留在同一个地方或移动不同数量的像素。如果上述方法不可行,那么撤消我的最后一次提交并将其替换为将整个视图向右滑动的选项也是一个可行的解决方案。

我感谢任何人提供的任何帮助,从快速的指针和想法一直到编码 sn-ps 或 github 提交。当然,如果您愿意,欢迎您 fork my repo。我将继续参与这个问题,以确保任何成功的解决方案都提交给 github 并在此处完整记录。非常感谢您的宝贵时间!

更新的想法

自从我的第一篇文章以来,我一直在思考这个问题,并意识到在视图中相对于其他文本项移动一些文本项可能会破坏原始博客文章中解决的一些原始性能目标。所以在这一点上,我正在考虑一个解决方案,其中整个单个子视图被动画到它的新位置可能是最好的。

其次,如果以这种方式完成,可能会出现子视图具有自定义颜色或渐变背景的情况。希望这可以通过这样一种方式完成,即在其正常位置,背景向左延伸到看不见的程度,这样当视图向右滑动时,自定义背景在整个单元格中仍然可见。

【问题讨论】:

  • 好问题...感谢

标签: iphone objective-c cocoa-touch ios


【解决方案1】:

感谢Craig's answer 为我指明了正确的方向,我有一个解决方案。我恢复了我的commit,它根据编辑模式移动了文本位置,并将其替换为a new solution,它在任何时候调用 layoutSubviews 时都会将整个内容视图设置到正确的位置,这会在切换时产生自动动画编辑模式:

- (void)layoutSubviews
{
    CGRect b = [self bounds];
    b.size.height -= 1; // leave room for the separator line
    b.size.width += 30; // allow extra width to slide for editing
    b.origin.x -= (self.editing) ? 0 : 30; // start 30px left unless editing
    [contentView setFrame:b];
    [super layoutSubviews];
}

通过这样做,我能够删除 ABTableViewCell.m 中的 setFrame: override,因为它以前的逻辑加上我的添加现在可以在 layoutSubviews 中找到。

我在单元格上设置了一个浅灰色背景,以验证自定义背景是否正常工作,而不会让我们看到它的背后,因为它来回移动并且看起来效果很好。

再次感谢 Craig 和其他对此进行调查的人。

此解决方案的 GitHub 提交:(link)

【讨论】:

  • 您的解决方案看起来很完美,正是我的想法。很高兴它成功了。 :)
  • 我有这个确切的问题,使用确切的代码。如果我在把头撞到墙上几个小时之前先看看这里,我会为自己节省一些额头瘀伤。您的解决方案完美运行。谢谢。
  • 如果您正在使用自动布局并且只想调整约束,这也适用 - 它会为约束调整设置动画。
【解决方案2】:

您目前如何移动文本?或者更具体地说,您在哪个 UITableViewCell 方法中执行移动?

根据我的经验,覆盖layoutSubviews 方法并在此处设置框架将自动包裹在动画中。

例如:

- (void)layoutSubviews {
    if (self.editing) {
        [titleLabel setFrame:CGRectMake(62, 6, 170, 24)];
    }
    else {
        [titleLabel setFrame:CGRectMake(30, 6, 200, 24)];
    }
    [super layoutSubviews];
}

【讨论】:

  • 嗨 Craig,绘图目前是在 FirstLastExampleTableViewCell 的 -(void)drawContentView:(CGRect)r 方法中完成的,该方法是从 ABTableViewCell 对 UITableViewCell 的 -(void)drawRect:(CGRect)r 方法的覆盖调用的。代码在这里:github.com/adamalex/fast-scrolling
  • 您的解决方案在使用多个子视图的情况下看起来不错,但这里有一个包含整个单元格内容的自定义绘制子视图。可能 layoutSubviews 也将是关键,我会对此进行调查并感谢任何其他想法,谢谢!
  • 我不确定使用他们的方法效果如何,因为文本直接绘制到屏幕上,而不是嵌入到 UIView 或任何支持 CoreAnimation 的对象中。与仅使用 UITextField/UITextView 相比,此方法是否有显着改进?
  • 再次感谢克雷格,这是朝着正确方向迈出的一大步!请参阅我发布的答案以获取有关我如何使用此信息的信息。还有关于性能,它在我链接的博客文章中解释了更多;对于复杂的单元格布局,性能提升似乎最为明显。
【解决方案3】:

为了完全控制自定义单元格中的编辑,您应该覆盖 UITableViewCell 子类中的 willTransitionToState 方法并检查状态掩码

- (void)willTransitionToState:(UITableViewCellStateMask)state
{
    NSString *logStr = @"Invoked";
    if ((state & UITableViewCellStateShowingEditControlMask)
        != 0) {
        // you need to move the controls in left
        logStr = [NSString stringWithFormat:@"%@
                  %@",logStr,@"UITableViewCellStateShowingEditControlMask"];
    }
    if ((state & UITableViewCellStateShowingDeleteConfirmationMask)
        != 0) {
        // you need to hide the controls for the delete button
        logStr = [NSString stringWithFormat:@"%@
                  %@",logStr,@"UITableViewCellStateShowingDeleteConfirmationMask"];
    }
    NSLog(@"%@",logStr);
    [super willTransitionToState:state];
}

你也可以覆盖 layoutSubviews

- (void)layoutSubviews {
    // default place for label
    CGRect alarmTimeRect = CGRectMake(37, 7, 75, 30);
    if (self.editing && !self.showingDeleteConfirmation) {
        // move rect in left
        alarmTimeRect = CGRectMake(77, 7, 75, 30);
    }
    [alarmTimeLabel setFrame:alarmTimeRect];
    [super layoutSubviews];
}

【讨论】:

  • 这是一个更好的解决方案。有关您获得的掩码的更多有用信息在这里: typedef enum : NSUInteger { UITableViewCellStateDefaultMask = 0, UITableViewCellStateShowingEditControlMask = 1
【解决方案4】:

还要处理滑动:(self.editing && !self.showingDeleteConfirmation)

【讨论】:

【解决方案5】:

我也有这个问题:如何为自定义编辑模式设置动画?我不是很喜欢这里的解决方案,所以我决定稍微思考一下并找到一个不同的解决方案。我不知道它是否更好,但我更喜欢那个。所以我决定在这里分享:

在自定义单元格中(继承自UITableViewCell),只需重载setEditing:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    [super setEditing:editing animated:animated];

    if (animated) {
        [UIView beginAnimations:@"setEditingAnimation" context:nil];
        [UIView setAnimationDuration:0.3];
    }

    if (editing) {
        /* do your offset and resize here */
    } else {
        /* return to the original here*/
    }

    if (animated)
        [UIView commitAnimations];
}

我不检查编辑值是否相同,但这只是我如何做到的一个想法。

【讨论】:

    【解决方案6】:

    实际上有四种编辑状态。

    UITableViewCellStateDefaultMask = 0

    UITableViewCellStateShowingEditControlMask = 1

    UITableViewCellStateShowingDeleteConfirmationMask = 1

    UITableViewCellStateShowingEditControlMask 和 UITableViewCellStateShowingDeleteConfirmationMask = (1

    让我感到困惑的是,当状态 3 转换到状态 1 时,不会调用任何选择器,它没有使用 self.showingDeleteConfirmation 来更改布局在 iOS7。因此,为了明确状态 2 和状态 3,我添加了一个实例变量来实现它。它对我很有用。

    -(void)willTransitionToState:(UITableViewCellStateMask)state{
        [super willTransitionToState:state];
    
        //Custom delete button from
        //http://stackoverflow.com/questions/19159476/uitableviewcelldeleteconfirmationcontrol-issue
        if((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask){
            [self recurseAndReplaceSubViewIfDeleteConfirmationControl:self.subviews];
            [self performSelector:@selector(recurseAndReplaceSubViewIfDeleteConfirmationControl:) withObject:self.subviews afterDelay:0];
        }
    
        _swipeDelete = NO;
    
        if(state==2){
            //Swipe to delete confirm
            _swipeDelete = YES;
        }
    
        if(state==3){
            //Edit state to delete confirm
        }
    }
    
    - (void)layoutSubviews{
    
        [super layoutSubviews];
    
        self.contentView.frame = CGRectMake(10, 5.0, 300, self.frame.size.height - 10);
    
        if(self.editing){
            self.contentView.frame = CGRectMake(40, 5.0, 270, self.frame.size.height - 10);
        }
    
        if(_swipeDelete){
            self.contentView.frame = CGRectMake(10, 5.0, 300, self.frame.size.height - 10);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多