UITableViewCell doesn't get deselected when swiping back quickly

后端 未结 16 1367
甜味超标
甜味超标 2021-01-29 23:49

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 contro

相关标签:
16条回答
  • 2021-01-30 00:28

    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. The folks behind Castro have posted an excellent analysis and solution to this: 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];
                }
            }];
        }
    }
    
    0 讨论(0)
  • 2021-01-30 00:28

    Codestage provided by far the best looking answer, so I decided to convert it into 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)
                    }
                })
            }
        }
    
    0 讨论(0)
  • 2021-01-30 00:29

    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.

    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];
    }
    
    0 讨论(0)
  • 2021-01-30 00:32

    Codestage answer, in Swift 3. notifyWhenInteractionEnds is deprecated.

    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)
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-30 00:36

    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. 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:

    self.clearsSelectionOnViewWillAppear = NO;
    

    and add the property for 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

    0 讨论(0)
  • 2021-01-30 00:37

    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.

    0 讨论(0)
提交回复
热议问题