扩展 UIScrollView 交互区域,区分滑动和点击
Expand UIScrollView interactive area and differentiate swiping and tapping
我正在使用 UIScroll View 制作具有分页功能的类似画廊的 ui。基本上是这样的:
因为需要分页,所以我把scrollview的宽度设置为单页的宽度,在我的例子中就是粉色矩形的宽度。
但我还想要两样东西:
- 点击黄色或蓝色区域会将相应的矩形带到中心。
- 黄色或蓝色区域(滚动视图外)可以scroll/swipe,这意味着整个屏幕宽度都是可滚动的。
我关注了this thread并添加了- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
。 BUT这样做,我只能达到第二个目标。当我设置选择器或委托处理黄色和蓝色的点击反应时,它不起作用。有什么想法吗?
That answer you referenced 是我的最爱之一。它没有考虑您的第一个要求,但我认为它可以非常巧妙地处理它,只需添加一个点击手势识别器。
在您的 "ClipView" 上创建它:
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
[self.myClipView addGestureRecognizer:tapGR];
// myClipView is the view that contains the paging scroll view
- (void)tap: (UITapGestureRecognizer *)gr {
// there are a few challenges here:
// 1) get the tap location in the correct coordinate system
// 2) convert that to which "page" was tapped
// 3) scroll to that page
}
挑战 1) 很简单,感谢手势识别器,它回答 locationInView:
CGPoint location = [gr locationInView:self.scrollView];
对于挑战 2),我们需要计算出您的滚动视图中的哪个页面被点击了。给定页面宽度,这可以通过非常简单的算法来完成。
// assuming you have something like this
#define kPAGE_WIDTH // some float
// page is just how many page-width's are represented by location.y
NSInteger page = floor(location.y/kPAGE_WIDTH);
现在,挑战 3) 现在很容易了,因为我们可以直接将页面更改到它的滚动位置...
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
或者,全部在一个代码块中...
- (void)tap: (UITapGestureRecognizer *)gr {
CGPoint location = [gr locationInView:self.scrollView];
NSInteger page = floor(location.y/kPAGE_WIDTH);
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
}
编辑
您可能还想从手势识别器中排除 "current page" 区域。这只需通过在 tap 方法中限定测试即可完成。
唯一的技巧是在与滚动视图的框架(即剪辑视图)相同的坐标系中获取点击位置...
CGPoint locationInClipper = [gr locationInView:gr.view];
并且 SDK 提供了一个很好的测试方法...
BOOL inScrollView = [self.scrollView pointInside:locationInClipper withEvent:nil];
所以...
- (void)tap: (UITapGestureRecognizer *)gr {
CGPoint locationInClipper = [gr locationInView:gr.view];
BOOL inScrollView = [self.scrollView pointInside:locationInClipper withEvent:nil];
if (!inScrollView) {
CGPoint location = [gr locationInView:self.scrollView];
NSInteger page = floor(location.y/kPAGE_WIDTH);
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
}
}
我正在使用 UIScroll View 制作具有分页功能的类似画廊的 ui。基本上是这样的:
因为需要分页,所以我把scrollview的宽度设置为单页的宽度,在我的例子中就是粉色矩形的宽度。
但我还想要两样东西:
- 点击黄色或蓝色区域会将相应的矩形带到中心。
- 黄色或蓝色区域(滚动视图外)可以scroll/swipe,这意味着整个屏幕宽度都是可滚动的。
我关注了this thread并添加了- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
。 BUT这样做,我只能达到第二个目标。当我设置选择器或委托处理黄色和蓝色的点击反应时,它不起作用。有什么想法吗?
That answer you referenced 是我的最爱之一。它没有考虑您的第一个要求,但我认为它可以非常巧妙地处理它,只需添加一个点击手势识别器。
在您的 "ClipView" 上创建它:
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
[self.myClipView addGestureRecognizer:tapGR];
// myClipView is the view that contains the paging scroll view
- (void)tap: (UITapGestureRecognizer *)gr {
// there are a few challenges here:
// 1) get the tap location in the correct coordinate system
// 2) convert that to which "page" was tapped
// 3) scroll to that page
}
挑战 1) 很简单,感谢手势识别器,它回答 locationInView:
CGPoint location = [gr locationInView:self.scrollView];
对于挑战 2),我们需要计算出您的滚动视图中的哪个页面被点击了。给定页面宽度,这可以通过非常简单的算法来完成。
// assuming you have something like this
#define kPAGE_WIDTH // some float
// page is just how many page-width's are represented by location.y
NSInteger page = floor(location.y/kPAGE_WIDTH);
现在,挑战 3) 现在很容易了,因为我们可以直接将页面更改到它的滚动位置...
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
或者,全部在一个代码块中...
- (void)tap: (UITapGestureRecognizer *)gr {
CGPoint location = [gr locationInView:self.scrollView];
NSInteger page = floor(location.y/kPAGE_WIDTH);
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
}
编辑
您可能还想从手势识别器中排除 "current page" 区域。这只需通过在 tap 方法中限定测试即可完成。
唯一的技巧是在与滚动视图的框架(即剪辑视图)相同的坐标系中获取点击位置...
CGPoint locationInClipper = [gr locationInView:gr.view];
并且 SDK 提供了一个很好的测试方法...
BOOL inScrollView = [self.scrollView pointInside:locationInClipper withEvent:nil];
所以...
- (void)tap: (UITapGestureRecognizer *)gr {
CGPoint locationInClipper = [gr locationInView:gr.view];
BOOL inScrollView = [self.scrollView pointInside:locationInClipper withEvent:nil];
if (!inScrollView) {
CGPoint location = [gr locationInView:self.scrollView];
NSInteger page = floor(location.y/kPAGE_WIDTH);
CGFloat y = page * kPAGE_WIDTH;
[self.scrollView setContentOffset:CGPointMake(y, 0.0f) animated:YES];
}
}