简体   繁体   English

快速向后滑动时,UITableViewCell不会被取消选中

[英]UITableViewCell doesn't get deselected when swiping back quickly

I've now updated three of my apps to iOS 7, but in all three, despite them not sharing any code, I have the problem where if the user swipes to go back in the navigation controller (rather than tap the back button) quickly, the cell will remain in its selected state. 我现在已经将我的三个应用程序更新到了iOS 7,但是在这三个应用程序中,尽管它们没有共享任何代码,但我遇到的问题是,如果用户滑动以返回导航控制器(而不是快速点击后退按钮) ,细胞将保持其选定状态。

For the three apps, one uses custom cells created programmatically, another uses custom cells created in a storyboard and the third uses default cells in a very basic subclass of UITableView, also in a storyboard. 对于这三个应用程序,一个使用以编程方式创建的自定义单元格,另一个使用在故事板中创建的自定义单元格,第三个使用UITableView的一个非常基本的子类中的默认单元格,也在故事板中。 In all three cases, the cells don't deselect by themselves. 在所有三种情况下,细胞不会自行取消选择。 If the user swipes slowly, or hits the back button, they deselect as normal. 如果用户缓慢滑动或按下后退按钮,则会正常取消选择。

This is only happening in my iOS 7 apps, Apple's own apps and third party apps upgraded for iOS 7 all seem to be behaving normally (albeit with slight differences in how quickly the cells gets deselected). 这只发生在我的iOS 7应用程序中,Apple自己的应用程序和为iOS 7升级的第三方应用程序似乎都表现正常(虽然细胞取消选择的速度略有不同)。

There must be something I'm doing wrong, but I'm not sure what? 一定有什么我做错了,但我不确定是什么?

This worked best for me: 这对我来说效果最好:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.clearsSelectionOnViewWillAppear = NO;
}

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}

I even got a much better unselect fading while I was swiping back slowly. 当我慢慢地向后滑动时,我甚至有一个更好的未选择性褪色。

I'm dealing with the same problem right now. 我现在正处理同样的问题。 The UICatalog -sample from Apple seems to bring the dirty solution. 来自Apple的UICatalog -sample似乎带来了肮脏的解决方案。

It really doesn't make me happy at all. 它真的不会让我开心。 As mentioned before it uses [self.tableView deselectRowAtIndexPath:tableSelection animated:NO]; 如前所述它使用[self.tableView deselectRowAtIndexPath:tableSelection animated:NO]; to deselect the currently selected row. 取消选择当前选定的行。

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

    // this UIViewController is about to re-appear, make sure we remove the current selection in our table view
    NSIndexPath *tableSelection = [self.tableView indexPathForSelectedRow];
    [self.tableView deselectRowAtIndexPath:tableSelection animated:NO];

    // some over view controller could have changed our nav bar tint color, so reset it here
    self.navigationController.navigationBar.tintColor = [UIColor darkGrayColor];
}

I have to mention the sample code may not be 我不得不提一下示例代码 iOS 7 IOS 7 iOS 8 iOS 8 iOS 9 iOS 9 iOS 10-ready iOS 10准备好了


Something which really confuses me is the UITableViewController Class Reference : 真正令我困惑的是UITableViewController类参考

When the table view is about to appear the first time it's loaded, the table-view controller reloads the table view's data. 当表视图即将在第一次加载时出现时,表视图控制器会重新加载表视图的数据。 It also clears its selection (with or without animation, depending on the request) every time the table view is displayed. 每次显示表格视图时,它还会清除其选择(有或没有动画,具体取决于请求)。 The UITableViewController class implements this in the superclass method viewWillAppear: . UITableViewController类在超类方法viewWillAppear:实现它viewWillAppear: You can disable this behavior by changing the value in the clearsSelectionOnViewWillAppear property. 您可以通过更改clearsSelectionOnViewWillAppear属性中的值来禁用此行为。

This is exactly the behavior I expect… but it does not seem to work. 这正是我期望的行为......但它似乎不起作用。 Neither for you nor for me. 既不适合你,也不适合我。 We really have to use the "dirty" solution and do it on our own. 我们真的必须使用“脏”的解决方案,并自己做。

Fabio's answer works well but doesn't give the right look if the user swipes just a little bit and then changes their mind. Fabio的答案效果很好,但如果用户只是稍微滑动然后改变主意就不会给出正确的效果。 In order to get that case right you need to save the selected index path and reset it when necessary. 为了使这种情况正确,您需要保存选定的索引路径并在必要时重置它。

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.savedSelectedIndexPath = nil;
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if (self.savedSelectedIndexPath) {
        [self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.savedSelectedIndexPath = self.tableView.indexPathForSelectedRow;

    if (self.savedSelectedIndexPath) {
        [self.tableView deselectRowAtIndexPath:self.savedSelectedIndexPath animated:YES];
    }
}

If using a UITableViewController, make sure to disable the built-in clearing: 如果使用UITableViewController,请确保禁用内置清除:

self.clearsSelectionOnViewWillAppear = NO;

and add the property for savedSelectedIndexPath: 并为savedSelectedIndexPath添加属性:

@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;

If you need to do this in a few different classes it might make sense to split it out in a helper, for example like I did in this gist: https://gist.github.com/rhult/46ee6c4e8a862a8e66d4 如果您需要在几个不同的类中执行此操作,可能需要将其拆分为帮助程序,例如我在此要点中所做的: https//gist.github.com/rhult/46ee6c4e8a862a8e66d4

This solution animates the row deselection along with the transition coordinator (for a user-driven VC dismiss) and re-applies the selection if the user cancels the transition. 此解决方案为行取消选择和转换协调器(用于用户驱动的VC解除)设置动画,并在用户取消转换时重新应用选择。 Adapted from a solution by Caleb Davenport in Swift. 改编自Ciftb Davenport在Swift中的解决方案。 Only tested on iOS 9. Tested as working with both user driven (swipe) transition and the old-style "Back" button tap. 仅在iOS 9上测试。经测试同时使用用户驱动(滑动)过渡和旧式“后退”按钮。

In the UITableViewController subclass: UITableViewController子类中:

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

    // Workaround. clearsSelectionOnViewWillAppear is unreliable for user-driven (swipe) VC dismiss
    NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
    if (indexPath && self.transitionCoordinator) {
        [self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            [self.tableView deselectRowAtIndexPath:indexPath animated:animated];
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            if ([context isCancelled]) {
                [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
            }
        }];
    }
}

After running into this myself today I found out that this apparently is a fairly well-known problem with UITableView, its support for interactive navigation transitions is slightly broken. 在我今天遇到这个问题之后,我发现这显然是UITableView的一个相当着名的问题,它对交互式导航过渡的支持略有破坏。 The folks behind Castro have posted an excellent analysis and solution to this: http://blog.supertop.co/post/80781694515/viewmightappear 卡斯特罗背后的人们已经发布了一个很好的分析和解决方案: http//blog.supertop.co/post/80781694515/viewmightappear

I decided to use their solution which also considers cancelled transitions: 我决定使用他们的解决方案,也考虑取消转换:

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

    NSIndexPath *selectedRowIndexPath = [self.tableView indexPathForSelectedRow];
    if (selectedRowIndexPath) {
        [self.tableView deselectRowAtIndexPath:selectedRowIndexPath animated:YES];
        [[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
            if ([context isCancelled]) {
                [self.tableView selectRowAtIndexPath:selectedRowIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
            }
        }];
    }
}

You can try to set 你可以尝试设置

self.clearsSelectionOnViewWillAppear = YES;

in a UITableViewController or 在UITableViewController或

[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO];

in viewWillAppear, maybe before calling [super viewWillAppear:animated]; 在viewWillAppear中,也许在调用[super viewWillAppear:animated]之前; If your UItableView is not inside an UITableViewController you must deselect the cells manually: 如果您的UItableView 不在 UITableViewController中,则必须手动取消选择单元格:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
}

I'm using 我正在使用

[tableView deselectRowAtIndexPath:indexPath animated:YES];

at the end of method 在方法结束时

(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Like this: 像这样:

(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    //doing something according to selected cell...

    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

Simple Swift 3/4 Answer: 简单的Swift 3/4答案:

override func viewWillAppear(_ animated: Bool) {
    if tableView.indexPathForSelectedRow != nil {
        self.tableView.deselectRow(at: tableView.indexPathForSelectedRow! as IndexPath, animated: true)
    }
}

Use 使用

[tableView deselectRowAtIndexPath:indexPath animated:YES];

code in 代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method

I've found a very simple solution to this problem that just makes the default behavior work as it should. 我找到了一个非常简单的解决方案,只是让默认行为正常工作。 I wasn't satisfied with the solutions involving deselectRowAtIndexPath since the resulting visual effect was slightly different. 我对deselectRowAtIndexPath的解决方案不满意,因为产生的视觉效果略有不同。

All you have to do in order to prevent this weird behavior is to reload the table when the view is displayed: 为了防止这种奇怪的行为,你所要做的就是在显示视图时重新加载表:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.tableView reloadData];
}

Codestage answer , in Swift 3. notifyWhenInteractionEnds is deprecated. Codestage答案 ,在Swift 3中。不推荐使用notifyWhenInteractionEnds

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)

    if let indexPath = self.tableView.indexPathForSelectedRow {
        self.tableView.deselectRow(at: indexPath, animated: true)
        self.transitionCoordinator?.notifyWhenInteractionChanges { (context) in
            if context.isCancelled {
                self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
            }
        }
    }
}

You are probably not calling the super view's viewWillAppear method ([super viewWillAppear:animated];). 您可能没有调用超级视图的viewWillAppear方法([super viewWillAppear:animated];)。 When you do this and the UITableViewController's parameter clearsSelectionOnViewWillAppear is YES then the cells will be deselected on viewWillAppear. 执行此操作并且UITableViewController的参数clearsSelectionOnViewWillAppear为YES时,将在viewWillAppear上取消选择单元格。

Based on Rhult 's code, I made a few changes. 根据Rhult的代码,我做了一些改动。

This implementation allow user to cancel swipe back and still keep selected for future swipe back deselect animation 此实现允许用户取消向后滑动并仍然保持选定状态以供将来滑动取消选择动画

@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;


- (void)viewDidLoad {
   [super viewDidLoad];
   self.clearsSelectionOnViewWillAppear = NO;
}

-(void) viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
   self.savedSelectedIndexPath = nil;
}

-(void) viewWillDisappear:(BOOL)animated {
   [super viewWillDisappear:animated];
   if (self.savedSelectedIndexPath && ![self.tableView indexPathForSelectedRow]) {
       [self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
   } else {
      self.savedSelectedIndexPath = [self.tableView indexPathForSelectedRow];
   }
}

Rhult's solution works perfectly on iOS 9.2. Rhult的解决方案在iOS 9.2上完美运行。 This is the implementation in Swift: 这是Swift中的实现:

Declare a variable in your MasterViewController to save the IndexPath: MasterViewController声明一个变量来保存IndexPath:

var savedSelectedIndexPath: NSIndexPath?

Then you can put the code in an extension for clarity: 然后,为了清楚起见,您可以将代码放在扩展名中:

extension MasterViewController {
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.savedSelectedIndexPath = nil
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        if let indexPath = self.savedSelectedIndexPath {
            self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.savedSelectedIndexPath = tableView.indexPathForSelectedRow
        if let indexPath = self.savedSelectedIndexPath {
            self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
        }
    }
}

Codestage provided by far the best looking answer , so I decided to convert it into Swift 2. Codestage提供了迄今为止最好看的答案 ,因此我决定将其转换为Swift 2。

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)

        let selectedRowIndexPath = self.tableView.indexPathForSelectedRow
        if ((selectedRowIndexPath) != nil) {
            self.tableView.deselectRowAtIndexPath(selectedRowIndexPath!, animated: true)
            self.transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock({ context in
                if (context.isCancelled()) {
                    self.tableView.selectRowAtIndexPath(selectedRowIndexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
                }
            })
        }
    }

For swift 对于迅捷

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    guard let indexPath = tableView.indexPathForSelectedRow else{
        return
    }
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在滚动之前,UITableViewCell按钮不会显示选中或取消选中状态 - UITableViewCell button doesn't show selected or deselected state until scroll 滑动UITableViewCell时不显示“删除” - “Delete” isn't showing when swiping a UITableViewCell 集合视图旧图标不会被取消选择 - Collection View old icon doesn't get deselected 在willDisplayCell中将UITableViewCell设置为YES:并且不能再取消选择单元格 - Set UITableViewCell selected to YES in willDisplayCell: and the cell can't be deselected anymore 在UITableViewCell上滑动时如何配置阈值/距离 - How to configure threshold/distance when swiping on UITableViewCell UITableViewCell不断被取消选择 - UITableViewCell keeps getting deselected 触摸并按住然后滑动时,“滚动视图”不会滚动 - Scroll View doesn't scroll when touching and holding then swiping 如何获取布尔值以指示在滑动操作期间是否在UITABLEVIEWCELL中进行滑动? - How to get a boolean that indicate whether it is swiping in UITABLEVIEWCELL when it is during the swipe action? 未显示将子视图添加到UITableViewCell - Adding a SubView to UITableViewCell doesn't get displayed 当包含在 UITableViewCell 中时,UIDatePicker 不起作用 - UIDatePicker doesn't work when included in a UITableViewCell
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM