自定义 UITableViewCell 上的 UIGestureRecognizer。轻敲多个细胞
UIGestureRecognizer on custom UITableViewCell. Tapping fires on multiple cells
我在这个奇怪的问题上到处搜索都无济于事。我有一个自定义的子类 UITableViewCell。正面和背面的两个视图,点击时单元格翻转。这是这样做的:
- (IBAction)cellFrontTapped:(id)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (_cellFlag == 0)
{
_cellFlag = 1;
[UIView transitionFromView:_cellFrontView toView:_cellBackView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[self performSelector:@selector(cellBackTapped:) withObject:self afterDelay:15.0];
}
}
- (IBAction)cellBackTapped:(id)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (_cellFlag == 1)
{
_cellFlag = 0;
[UIView transitionFromView:_cellBackView toView:_cellFrontView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
}
}
这只适用于几个单元格。最多几页价值。但是当我加载一个更大的数据集时,点击一个单元格会像预期的那样翻转它,但也会翻转其他单元格。
我意识到这是因为细胞被 dequeueReusableCellWithIdentifier
重复使用,但我无法破译如何防止它。
我试过将它实现为一个 UIGestureRecognizer
。我试过像这样使用 didSelectRowAtIndexPath
:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = (MyTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
if (cell.cellFlag == 0)
{
[cell cellFrontTapped];
}
else
{
[cell cellBackTapped];
}
}
这些都可以正确翻转单元格,但点击事件总是翻转列表中的其他单元格。我找到的唯一解决方案是不要像这样使用 dequeueReusableCellWithIdentifier
:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
这是我当前的子类实现:
@implementation MyTableViewCell
- (void)awakeFromNib {
// Adding the recognizer here produced the same result
//UIGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapped)];
//tap.delegate = self;
//[self addGestureRecognizer:tap];
_cellFlag = 0;
}
- (void)cellFrontTapped {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_cellFlag = 1;
[UIView transitionFromView:_cellFrontView toView:_cellBackView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[self performSelector:@selector(cellBackTapped) withObject:self afterDelay:15.0];
}
- (void)cellBackTapped {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_cellFlag = 0;
[UIView transitionFromView:_cellBackView toView:_cellFrontView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
}
-(void)cellTapped
{
if (_cellFlag == 0)
{
[self cellFrontTapped];
}
else
{
[self cellBackTapped];
}
}
@end
这是`configureCell:atIndexpath:
- (void)configureCell:(MyTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath
{
NSManagedObject *t = [[self fetchedResultsController] objectAtIndexPath:indexPath];
//here i set the labels and such
cell.cellBackAmountLabel.text = [t.amount formattedAmount];
//added
if ([self.flippedCellIndexes containsObject:indexPath])
{
[cell.contentView bringSubviewToFront:cell.cellBackView];
}
else
{
[cell.contentView bringSubviewToFront:cell.cellFrontView];
}
}
我很茫然。在我的案例中,不使用 dequeueReusableCellWithIdentifier
会对性能产生重大影响。求助!
我建议将模型与视图分开。这意味着您应该跟踪哪些单元格应该呈现为翻转,而不是在单元格本身上。假设您在视图控制器中声明了一个名为 flippedIndexes
的 NSArray
(可能 NSMutableArray
,甚至)。
如果你的数据集像你说的那么大,那么你可能应该使用稀疏数组而不是 NSArray
。稀疏数组可以很容易地用 NSMutableDictionary
来实现。 NSMutableSet
也可以。
当单元格出列时,您将检查应该翻转哪些单元格,可能是您的 configureCell:atIndexPath:
方法。基本上,如果 indexPath
显示在您的稀疏数组上或设置您将单元格渲染为翻转。这意味着删除您在单元格上声明的 cellFlag
属性 并根据我一直提到的模型切换其状态。要翻转单元格,请检查给定 indexPath
的 flippedIndexes
属性 并相应地执行操作。像这样:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = (MyTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
if (![self.flippedIndexes containsObject:indexPath])
{
[cell cellFrontTapped];
[self.flippedIndexes addObject:indexPath];
}
else
{
[cell cellBackTapped];
[self.flippedIndexes removeObject:indexPath];
}
}
这里我假设 NSMutableSet
用于 flippedIndexes
属性。请注意,只有在 configureCell:atIndexPath:
中检查模型时,这才会正常工作,否则滚动时单元格会神奇地清除。
这个故事的寓意是:不要在排队的单元格中存储状态信息。
我在这个奇怪的问题上到处搜索都无济于事。我有一个自定义的子类 UITableViewCell。正面和背面的两个视图,点击时单元格翻转。这是这样做的:
- (IBAction)cellFrontTapped:(id)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (_cellFlag == 0)
{
_cellFlag = 1;
[UIView transitionFromView:_cellFrontView toView:_cellBackView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[self performSelector:@selector(cellBackTapped:) withObject:self afterDelay:15.0];
}
}
- (IBAction)cellBackTapped:(id)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (_cellFlag == 1)
{
_cellFlag = 0;
[UIView transitionFromView:_cellBackView toView:_cellFrontView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
}
}
这只适用于几个单元格。最多几页价值。但是当我加载一个更大的数据集时,点击一个单元格会像预期的那样翻转它,但也会翻转其他单元格。
我意识到这是因为细胞被 dequeueReusableCellWithIdentifier
重复使用,但我无法破译如何防止它。
我试过将它实现为一个 UIGestureRecognizer
。我试过像这样使用 didSelectRowAtIndexPath
:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = (MyTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
if (cell.cellFlag == 0)
{
[cell cellFrontTapped];
}
else
{
[cell cellBackTapped];
}
}
这些都可以正确翻转单元格,但点击事件总是翻转列表中的其他单元格。我找到的唯一解决方案是不要像这样使用 dequeueReusableCellWithIdentifier
:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
这是我当前的子类实现:
@implementation MyTableViewCell
- (void)awakeFromNib {
// Adding the recognizer here produced the same result
//UIGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapped)];
//tap.delegate = self;
//[self addGestureRecognizer:tap];
_cellFlag = 0;
}
- (void)cellFrontTapped {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_cellFlag = 1;
[UIView transitionFromView:_cellFrontView toView:_cellBackView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[self performSelector:@selector(cellBackTapped) withObject:self afterDelay:15.0];
}
- (void)cellBackTapped {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_cellFlag = 0;
[UIView transitionFromView:_cellBackView toView:_cellFrontView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
}
-(void)cellTapped
{
if (_cellFlag == 0)
{
[self cellFrontTapped];
}
else
{
[self cellBackTapped];
}
}
@end
这是`configureCell:atIndexpath:
- (void)configureCell:(MyTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath
{
NSManagedObject *t = [[self fetchedResultsController] objectAtIndexPath:indexPath];
//here i set the labels and such
cell.cellBackAmountLabel.text = [t.amount formattedAmount];
//added
if ([self.flippedCellIndexes containsObject:indexPath])
{
[cell.contentView bringSubviewToFront:cell.cellBackView];
}
else
{
[cell.contentView bringSubviewToFront:cell.cellFrontView];
}
}
我很茫然。在我的案例中,不使用 dequeueReusableCellWithIdentifier
会对性能产生重大影响。求助!
我建议将模型与视图分开。这意味着您应该跟踪哪些单元格应该呈现为翻转,而不是在单元格本身上。假设您在视图控制器中声明了一个名为 flippedIndexes
的 NSArray
(可能 NSMutableArray
,甚至)。
如果你的数据集像你说的那么大,那么你可能应该使用稀疏数组而不是 NSArray
。稀疏数组可以很容易地用 NSMutableDictionary
来实现。 NSMutableSet
也可以。
当单元格出列时,您将检查应该翻转哪些单元格,可能是您的 configureCell:atIndexPath:
方法。基本上,如果 indexPath
显示在您的稀疏数组上或设置您将单元格渲染为翻转。这意味着删除您在单元格上声明的 cellFlag
属性 并根据我一直提到的模型切换其状态。要翻转单元格,请检查给定 indexPath
的 flippedIndexes
属性 并相应地执行操作。像这样:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = (MyTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
if (![self.flippedIndexes containsObject:indexPath])
{
[cell cellFrontTapped];
[self.flippedIndexes addObject:indexPath];
}
else
{
[cell cellBackTapped];
[self.flippedIndexes removeObject:indexPath];
}
}
这里我假设 NSMutableSet
用于 flippedIndexes
属性。请注意,只有在 configureCell:atIndexPath:
中检查模型时,这才会正常工作,否则滚动时单元格会神奇地清除。
这个故事的寓意是:不要在排队的单元格中存储状态信息。