UIScrollView自定义分页

我的问题与我正在尝试使用滚动器的自定义分页forms有关,如果您首先考虑在老虎机中实现的滚动视图的types,则更容易可视化。

所以说我的UIScrollView有100像素的宽度。 假设它包含3个内部视图,每个视图的宽度为30个像素,使得它们以3个像素的宽度分隔。 我想实现的分页types是,每个页面是我的意见(30像素)之一,而不是滚动视图的整个宽度。

我知道,通常,如果视图占用整个滚动视图的宽度,并启用分页,那么一切正常。 但是,在我的自定义分页中,我也希望滚动视图中的周围视图也可见。

我将如何做到这一点?

我刚刚为另一个项目做了这个。 你需要做的是把UIScrollView放到UIView的自定义实现中。 我为这个叫做ExtendedHitAreaViewController的类创build了一个类。 ExtendedHitAreaView覆盖hitTest函数返回它的第一个子对象,这将是你的滚动视图。

你的滚动视图应该是你想要的页面大小,即30px与clipsToBounds = NO。 扩展命中区域视图应该是要显示的区域的全部大小,其中clipsToBounds = YES。

将滚动视图作为子视图添加到扩展命中区域视图,然后将扩展命中区域视图添加到您的视图控制器的视图。

@implementation ExtendedHitAreaViewContainer - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if ([self pointInside:point withEvent:event]) { if ([[self subviews] count] > 0) { //force return of first child, if exists return [[self subviews] objectAtIndex:0]; } else { return self; } } return nil; } @end 

因为iOS 5有这样的委托方法: - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

所以你可以做这样的事情:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { if (scrollView == self.scrollView) { CGFloat x = targetContentOffset->x; x = roundf(x / 30.0f) * 30.0f; targetContentOffset->x = x; } } 

对于更高的速度,你可能想调整你的targetContentOffset有点不同,如果你想要一个更加活泼的感觉。

我有同样的问题,这对我来说很好,在iOS 8上testing。

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { NSInteger index = lrint(targetContentOffset->x/_pageWidth); NSInteger currentPage = lrint(scrollView.contentOffset.x/_pageWidth); if(index == currentPage) { if(velocity.x > 0) index++; else if(velocity.x < 0) index--; } targetContentOffset->x = index * _pageWidth; } 

我不得不检查速度,如果速度不为零,总是进入下一页/上一页,否则当做非常短而快的滑动操作时,会产生非animation跳转。

更新:这似乎工作得更好:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGFloat index = targetContentOffset->x/channelScrollWidth; if(velocity.x > 0) index = ceil(index); else if(velocity.x < 0) index = floor(index); else index = round(index); targetContentOffset->x = index * channelScrollWidth; } 

这些是水平滚动视图,使用y而不是x的垂直。

经过几天的研究和排除故障,我想出了一些适合我的东西!

首先,您需要inheritancescrollview所在的视图的子类,并使用以下内容覆盖此方法:

  -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { UIView* child = nil; if ((child = [super hitTest:point withEvent:event]) == self) return (UIView *)_calloutCell; return child; } 

然后所有的魔法都发生在scrollview委托方法中

  -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { //_lastOffset is declared in the header file //@property (nonatomic) CGPoint lastOffset; _lastOffset = scrollView.contentOffset; } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGPoint currentOffset = scrollView.contentOffset; CGPoint newOffset = CGPointZero; if (_lastOffset.x < currentOffset.x) { // right to left newOffset.x = _lastOffset.x + 298; } else { // left to right newOffset.x = _lastOffset.x - 298; } [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; [UIView setAnimationDelay:0.0f]; targetContentOffset->x = newOffset.x; [UIView commitAnimations]; } 

您还需要设置滚动视图的减速率。 我在ViewDidLoad中做了

  [self.scrollView setDecelerationRate:UIScrollViewDecelerationRateFast]; 

滚动视图内有许多不同的视图,button和手势识别器。

@ picciano的答案没有工作(滚动工作良好,但button和识别器没有得到触动),所以我发现这个解决scheme:

 class ExtendedHitAreaView : UIScrollView { // Your insets var hitAreaEdgeInset = UIEdgeInsets(top: 0, left: -20, bottom: 0, right: -20) override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { let hitBounds = UIEdgeInsetsInsetRect(bounds, hitAreaEdgeInset) return CGRectContainsPoint(hitBounds, point) } } 

alcides的解决scheme完美的作品。 我只是启用/禁用scrollview的滚动,每当我inputscrollviewDidEndDragging和scrollViewWillEndDragging。 如果用户在分页animation完成之前滚动了几次,则单元格略微不一致。

所以我有:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { scrollView.scrollEnabled = NO CGPoint currentOffset = scrollView.contentOffset; CGPoint newOffset = CGPointZero; if (_lastOffset.x < currentOffset.x) { // right to left newOffset.x = _lastOffset.x + 298; } else { // left to right newOffset.x = _lastOffset.x - 298; } [UIView animateWithDuration:0.4 animations:^{ targetContentOffset.x = newOffset.x }]; } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView { scrollView.scrollEnabled = YES }