我正在尝试实现类似于 iPhone 上的 闪卡 的需求。其中文本内容将位于卡片中心,左侧(上一张卡片)、右侧(下一张卡片)部分可见。
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(200, 400);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
好处在于,当用户点击左边或右边部分可见的单元格时,您可以轻松实现居中行为(这在某些UIScrollView hack中并不容易实现):
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[self.collectionView scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
}
UIScrollView
分页API来实现此操作,有一个简单的技巧。除了将pagingEnabled
设置为YES
之外,还要确保将clipsToBounds
设置为NO
。UIScrollView *scrollView = [UIScrollView new];
self.scrollView.pagingEnabled = YES;
self.scrollView.clipsToBounds = NO;
hitTest:
方法,始终返回滚动视图。- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return self.scrollView;
}
clipToBounds
设置为YES
,这将是滚动视图可见的区域。由于我的滚动视图非常小(仅100像素高),因此hitTest
方法获取整个视图控制器,这不是我想要的。这个解决方案适用于任何大小的ScrollView,并使用Swift 4完成:
class ScrollViewContainer: UIView {
@IBOutlet weak var scrollView: UIScrollView!
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard self.bounds.contains(point) else {
return super.hitTest(point, with: event)
}
guard self.scrollView.frame.contains(point) else {
return self.scrollView
}
return super.hitTest(point, with: event)
}
}
Guard
如果点击在其范围之外,则返回默认的UIView
hitTest
。Guard
如果点击在容器内但在ScrollView
之外,则返回UIScrollView
(这正是此问题的目标)。ScrollView
内部,则不需要进行任何不同的操作,只需让UIView
使用其默认实现处理即可。Guard
,但我认为这种方式更清晰地解释了逻辑。
UICollectionView
是UIScrollView
的子类,无需遍历其子视图。 - stefreak