【问题标题】:How to delay closing a modal window after selecting a UITableViewCell选择 UITableViewCell 后如何延迟关闭模式窗口
【发布时间】:2011-12-19 16:35:09
【问题描述】:

我对此进行了一些搜索,但希望我不会创建重复项(毕竟是凌晨 4 点)。我也希望这对大师来说是一个容易回答的问题,但我现在找不到。

我有一个 UITableView 用于应用程序设置。当您选择其中一行时,它会添加复选标记附件。由于它是一个模态窗口,我已将其设置为在您选择它后关闭该窗口。但是,我当前的代码会在您选择它时立即关闭窗口,并且您看不到选择动画(以及随后出现的复选标记)。我的模态窗口代码基于AddMusic 示例项目。

有没有办法在执行关闭命令之前让表格行闪烁几次,以便很明显选择了哪一行?

作为参考,我的模态窗口是UIViewController <UITableViewDelegate>

而我的选择行代码如下:

- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
    UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:self.selectedIndexPath];
    oldCell.accessoryType = UITableViewCellAccessoryNone;

    UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
    newCell.accessoryType = UITableViewCellAccessoryCheckmark;

    [self setSelectedIndexPath:indexPath];
    [tableView deselectRowAtIndexPath: indexPath animated: YES];

    // close the window when an option is selected.
    [self.delegate movieCinemaViewControllerDidFinish: self];
}

【问题讨论】:

  • 添加了我的模态窗口代码基于 Apple 的 AddMusic 示例项目这一事实。

标签: iphone objective-c ios uitableview


【解决方案1】:

要延迟关闭,请更改

[self.delegate movieCinemaViewControllerDidFinish: self];

到:

[self.delegate performSelector:@selector(movieCinemaViewControllerDidFinish:) withObject:self afterDelay:5];

要刷机,您可以使用类似的技术将多个de/selectRowAtIndexPath:s 排队。在此过程中禁用用户交互也可能是明智之举。就个人而言,我认为闪烁单元格是不必要的 - 只需将退出延迟几分之一秒就足以成为亮点?


另外安排一个 NSTimer 在延迟后调用 -(void)complete 方法,并让该方法调用委托的选择器。

【讨论】:

  • 感谢您的回答。延迟正是我所追求的,但我也看到过闪烁的应用程序,所以我认为它们可能是交织在一起的。
  • 刚试过;没有骰子,我害怕。 XCode 通知我找不到实例方法 -performSelector:withObject:afterDelay。
  • 你需要像 Bengie 的例子那样定义你的延迟。正因为如此, - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay 是 NSObject 的一种方法,你很可能有错别字。
  • 添加了替代解决方案
【解决方案2】:

我将创建一个带有动画方法的子类 UITableViewCell 来描述单元格选择。单元格将有一个协议,该协议会在动画完成时通知委托,因此委托(在本例中为您的 UIViewController)只有在单元格告诉它动画完成时才会关闭模式。

第 1 步是使用 subclassedCellSelected:(NSIndexPath*)myIndexPath 之类的方法在 UITableViewCell 的标头中创建一个委托协议

第 2 步是在您的单元格中声明一个 ivar,用于存储单元格的索引路径。将这个 ivar 声明为一个属性(当然是合成它),这样当你的 UIViewController 在 cellForRowAtIndexPath 中创建单元格时,你可以在单元格上设置 indexPath ivar。这会告诉单元格它的索引路径位置,并且在通知代表它的选择时会很有帮助。

第 3 步将是实现实际的动画方法:

- (void)startPulse
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationDuration:0.1];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(endPulse)];

    CGAffineTransform transform = CGAffineTransformMakeScale(0.9, 0.9);
    self.transform = transform;
    self.alpha = 0.5;

    [UIView commitAnimations];
}

- (void)endPulse
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationDuration:0.1];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(completeAction)];

    CGAffineTransform transform = CGAffineTransformMakeScale(1, 1);
    self.transform = transform;
    self.alpha = 1;

    [UIView commitAnimations];
}

- (void)completeAction
{
    if([self.delegate respondsToSelector:@selector(subclassedCellDelegate:)])
        [self.delegate subclassedCellSelected:self.indexPath];
}

在视图控制器的 didSelectRowAtIndexPath 方法中,您现在应该在单元格上调用 startPulse 方法。你可以这样做:

CustomTableViewCell *myCell = (CustomTableViewCell*)[tableView cellForRowAtIndexPath:indexPath]

[myCell startPulse];

要传递的 indexPath 是您从 didSelectRowAtIndexPath 回调中获得的。

现在发生的事情是单元格将启动它的动画方法,一旦动画完成,将发布 subclassedCellSelected 的委托回调。

您的 UIViewController 应该订阅自定义单元格的协议并在您的类文件中实现委托回调方法,如下所示:

- (void)subclassedCellSelected(NSIndexPath*)cellIndexPath
{
    //dismiss the modal here
}

如果您在设置委托协议方面需要帮助,请在此处查看我的答案:dismissModalViewController AND pass data back

这段代码最终会显示一个简单的动画,在该动画中我们的单元格在执行所需操作之前“弹跳”进出。

【讨论】:

  • 请注意,可能有一种更简单的方法来实现这一点(我不知道),但这是一种多年来一直为我工作的方法 :)
【解决方案3】:

实际上,如果您有一个仅是id 的委托,则不能指望performSelector:withObject:afterDelay 方法,因为它是来自NSObject 的NSDelayedPerforming 类别的方法。鉴于此,问题在于并非所有id 都一定是NSObject 类(例如,您的id 可以指向NSProxy 对象,该对象不继承自NSObject)

所以,你可以做的是使用一些 GCD 来完成延迟

double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.delegate movieCinemaViewControllerDidFinish: self];
});

【讨论】:

  • 已经在几个类似的情况下使用过,效果很好。
  • iOS 上没有 GCD。在这种情况下,最简单的解决方法是在延迟后对 self 执行选择器,并直接让 self 调用委托。我会为 NSProxy 投票(我不知道,但我认为它与问题无关)并为 GCD 投票,所以我让你的答案保持中立:)
  • 我不明白为什么no GCD on iOS... 文档的第一行说“Grand Central Dispatch (GCD) 包含语言功能、运行时库和系统增强功能,可提供系统性、全面的改进支持在 iOS 和 Mac OS X 中的多核硬件上并发执行代码。” developer.apple.com/library/ios/#documentation/Performance/…
  • 终于有时间完成这一点了。这很好用!谢谢:)
  • 哎呀我错过了我的预选赛,我的意思是有No GCD in iOS < 4.0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-29
  • 2022-06-30
相关资源
最近更新 更多