带有 UIScrollView 的 UICollectionViewCell 取消了 didSelectItemAtIndexPath
Posted
技术标签:
【中文标题】带有 UIScrollView 的 UICollectionViewCell 取消了 didSelectItemAtIndexPath【英文标题】:UICollectionViewCell with UIScrollView cancels didSelectItemAtIndexPath 【发布时间】:2013-01-12 22:33:31 【问题描述】:我有一个UICollectionView
,它可以水平滚动以一次显示一个UICollectionViewCell
。每个UICollectionViewCell
都有一个垂直滚动的UIScrollView
作为子视图,用于滚动单元格的内容。 UICollectionViewCell
的内部只有 90 % 左右被 UIScrollView
覆盖 - 即单元格的外框未被此覆盖。
事实证明,UICollectionViewCell
中被UIScrollView
覆盖的部分取消了UICollectionView
委托didSelectItemAtIndexPath
。因此,当在UIScrollView
内发生简单的点击时,此方法不 被调用,而如果点击发生在单元格的外部,即UIScrollView
之外,则此方法是 调用。
关于如何实现即使在UIScrollView
内点击也可以调用didSelectItemAtIndexPath
方法的设置的任何建议?
【问题讨论】:
【参考方案1】:我发现最有效的方法是窃取UIScrollView
暴露的panGestureRecognizer
,并禁用scrollView
上的userInteraction
。这样,您可以获得滚动视图的行为,但保持集合视图上的交互。在您的 UICollectionViewCell
子类上:
self.scrollView.userInteractionEnabled = NO;
[self.contentView addGestureRecognizer:self.scrollView.panGestureRecognizer];
这是 Apple 在 WWDC 2014 session 235(高级滚动视图和触摸处理技术)中推荐和演示的方法
【讨论】:
这个解决方案似乎是迄今为止解决这个问题的最干净的方法。谢谢! 这是一个很棒的解决方案,但如果你的 scrollView 包含按钮,它就不起作用:( 是的,这是最好的解决方案,因为它只需要 2 行代码,您仍然可以使用didSelectItemAtIndexPath
函数。干得好!【参考方案2】:
这是一个 UIScrollView 子类方法,它维护单元格选择功能,还允许在滚动视图内外进行 UIControl 选择(按钮等)。
斯威夫特 3
class CellContentScrollView: UIScrollView
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
let hitTargetView = super.hitTest(point, with: event)
return hitTargetView as? UIControl ?? (hitTargetView == self ? nil : superview)
override func didMoveToSuperview()
superview?.addGestureRecognizer(panGestureRecognizer)
斯威夫特 2
class CellContentScrollView: UIScrollView
// MARK: - UIView override
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
let hitTargetView = super.hitTest(point, withEvent: event)
return hitTargetView as? UIControl ?? (hitTargetView == self ? nil : superview)
override func didMoveToSuperview()
superview?.addGestureRecognizer(panGestureRecognizer)
Objective-C
@implementation CellContentScrollView
#pragma mark - UIView override
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
UIView *hitTargetView = [super hitTest:point withEvent:event];
if ([hitTargetView isKindOfClass:UIControl.class])
return hitTargetView;
else if (hitTargetView != self)
return self.superview;
return nil;
- (void)didMoveToSuperview
[self.superview addGestureRecognizer:self.panGestureRecognizer];
@end
【讨论】:
完美运行!谢谢 你拯救了我的一天!谢谢!【参考方案3】:点击UIScrollView
用于查看是否应该滚动。
您应该将catch the single tap on the UIScrollView 本身传递给周围的UICollectionViewCell
。
【讨论】:
谢谢!我发现这个答案好一点:***.com/a/5216518/746968 @Zappel 那么如何将点击转发到 UICollectionView 以模拟一个交互式选择点击,该点击也会触发 UICollectionView 的选择委托方法? -1 你应该明确地解释你将如何“将它传递给周围的 UICollectionViewCell”【参考方案4】:为您的超级视图添加点按手势
override func viewDidLoad()
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView(gesture:)))
view.addGestureRecognizer(tapGesture)
@objc func didTapView(gesture: UITapGestureRecognizer)
view.endEditing(true)
let touchLocation:CGPoint = gesture.location(ofTouch: 0, in: self.collectionView)
let indexPath = self.collectionView.indexPathForItem(at: touchLocation)
if indexPath != nil
let cell = self.collectionView.cellForItem(at: indexPath!)
if (cell?.isSelected)!
//PREFORM DESELECT
else
//PREFORM SELECT HERE
【讨论】:
以上是关于带有 UIScrollView 的 UICollectionViewCell 取消了 didSelectItemAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章
带有 IUViewController 的 UIScrollView 拖放对象
带有 ViewControllers 的 UIScrollView
带有 UIScrollView 的 ECSlidingViewController