Ios UIScrollView自定义分页 我的问题与一种定制的分页方式有关,我试图用一个滚动程序来做,如果你首先考虑在一个老虎机中实现的滚动视图的类型,这是很容易可视化的。

Ios UIScrollView自定义分页 我的问题与一种定制的分页方式有关,我试图用一个滚动程序来做,如果你首先考虑在一个老虎机中实现的滚动视图的类型,这是很容易可视化的。,ios,iphone,objective-c,uiview,uiscrollview,Ios,Iphone,Objective C,Uiview,Uiscrollview,假设我的UIScrollView的宽度为100像素。假设它包含3个内部视图,每个视图的宽度为30像素,这样它们之间的间隔宽度为3像素。我希望实现的分页类型是,每个页面都是我的一个视图(30像素),而不是滚动视图的整个宽度 我知道,通常情况下,如果视图占据了滚动视图的整个宽度,并且启用了分页,那么一切都正常。但是,在我的自定义分页中,我还希望滚动视图中的周围视图也可见 我该怎么做呢?我只是为另一个项目做的。您需要做的是将UIScrollView放入UIView的自定义实现中。我为此创建了一个名为E

假设我的UIScrollView的宽度为100像素。假设它包含3个内部视图,每个视图的宽度为30像素,这样它们之间的间隔宽度为3像素。我希望实现的分页类型是,每个页面都是我的一个视图(30像素),而不是滚动视图的整个宽度

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


我该怎么做呢?

我只是为另一个项目做的。您需要做的是将UIScrollView放入UIView的自定义实现中。我为此创建了一个名为ExtendedHitAreaViewController的类。ExtendedHitAreaView覆盖hitTest函数以返回其第一个子对象,即滚动视图

您的滚动视图应该是您想要的页面大小,即30像素,clipsToBounds=NO。 “扩展命中区域”视图应该是要显示的区域的完整大小,clipsToBounds=YES

将滚动视图作为子视图添加到扩展命中区域视图中,然后将扩展命中区域视图添加到viewcontroller的视图中

@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)ScrollViewWillendDraging:(UIScrollView*)scrollView with velocity:(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,使其稍有不同

经过几天的研究和故障排除,我找到了适合我的东西

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

    -(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];

      }

alcides的解决方案非常有效。只要输入ScrollViewDiEndDraging和ScrollViewWilEndDraging,我就启用/禁用scrollview的滚动。如果用户在分页动画完成之前滚动几次,则单元格会稍微不对齐

因此,我:

- (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
}
-(void)ScrollViewWillendDraging:(UIScrollView*)带速度的scrollView:(CGPoint)速度targetContentOffset:(inout CGPoint*)targetContentOffset{
scrollView.scrollEnabled=否
CGPoint currentOffset=scrollView.contentOffset;
CGPoint newOffset=CGPointZero;
如果(_lastOffset.x
我也有同样的问题,在iOS 8上测试后,这对我来说非常有效

- (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;
}
-(void)ScrollViewWillendDraging:(UIScrollView*)scrollView
withVelocity:(CGPoint)速度
targetContentOffset:(输入输出CGPoint*)targetContentOffset
{
NSInteger index=lrint(targetContentOffset->x/_pageWidth);
NSInteger currentPage=lrint(scrollView.contentOffset.x/_pageWidth);
如果(索引==currentPage){
如果(速度x>0)
索引++;
否则如果(速度x<0)
索引--;
}
targetContentOffset->x=索引*\u页面宽度;
}
我必须检查速度,如果速度不为零,则总是转到下一页/上一页,否则在进行非常短和快速的滑动时,它会给出非动画跳跃

更新:这似乎效果更好:

- (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;
}
-(void)ScrollViewWillendDraging:(UIScrollView*)scrollView
withVelocity:(CGPoint)速度
targetContentOffset:(输入输出CGPoint*)targetContentOffset
{
CGFloat index=targetContentOffset->x/通道滚动宽度;
如果(速度x>0)
指数=ceil(指数);
否则如果(速度x<0)
指数=楼层(指数);
其他的
指数=圆形(指数);
targetContentOffset->x=索引*通道宽度;
}

对于水平滚动视图,请使用
y
而不是
x
来显示垂直滚动视图。

我在滚动视图中有许多不同的视图,带有按钮和手势识别器

@picciano的答案对我来说不起作用(滚动效果很好,但按钮和识别器无法触摸),因此我找到了这个解决方案:

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)
    }
}

我一直在努力克服这个问题,我发现了一个几乎完美的解决方案,它可以满足您的需要,并且可以使用您想要的页面宽度

我从UIScrollView中将scrollView.isPaging设置为false(同时,默认为false),并将其委托设置为UIScrollViewDelegate

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    // Stop scrollView sliding:
    targetContentOffset.pointee = scrollView.contentOffset

    if scrollView == scrollView {
        let maxIndex = slides.count - 1
        let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
        var targetIndex = Int(round(Double(targetX / (pageWidth + spacingWidth))))
        var additionalWidth: CGFloat = 0
        var isOverScrolled = false

        if targetIndex <= 0 {
            targetIndex = 0
        } else {
            // in case you want to make page to center of View
            // by substract width with this additionalWidth
            additionalWidth = 20
        }

        if targetIndex > maxIndex {
            targetIndex = maxIndex
            isOverScrolled = true
        }

        let velocityX = velocity.x
        var newOffset = CGPoint(x: (CGFloat(targetIndex) * (self.pageWidth + self.spacingWidth)) - additionalWidth, y: 0)
        if velocityX == 0 {
            // when velocityX is 0, the jumping animation will occured
            // if we don't set targetContentOffset.pointee to new offset
            if !isOverScrolled &&  targetIndex == maxIndex {
                newOffset.x = scrollView.contentSize.width - scrollView.frame.width
            }
            targetContentOffset.pointee = newOffset
        }

        // Damping equal 1 => no oscillations => decay animation:
        UIView.animate(
            withDuration: 0.3, delay: 0,
            usingSpringWithDamping: 1,
            initialSpringVelocity: velocityX,
            options: .allowUserInteraction,
            animations: {
                scrollView.contentOffset = newOffset
                scrollView.layoutIfNeeded()
        }, completion: nil)
    }
}
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
//停止滚动视图滑动:
targetContentOffset.pointee=scrollView.contentOffset
如果scrollView==scrollView{
设maxIndex=slides.count-1
让targetX:CGFloat=scrollView.contentOffset.x+velocity.x*60.0
var targetIndex=Int(圆形(双精度)(targetX/(页面宽度+间距宽度)))
var附加宽度:CGFloat=0
var isOverScrolled=false
如果targetIndex maxIndex{
targetIndex=maxIndex
isOverScrolled=true
}
设velocityX=速度.x
var newOffset=CGPoint(x:(CGFloat(targetIndex)*(self.pageWidth+self.spacingWidth))-additionalWidth,y:0)
如果velocityX==0{
//当velocityX为
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    // Stop scrollView sliding:
    targetContentOffset.pointee = scrollView.contentOffset

    if scrollView == scrollView {
        let maxIndex = slides.count - 1
        let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
        var targetIndex = Int(round(Double(targetX / (pageWidth + spacingWidth))))
        var additionalWidth: CGFloat = 0
        var isOverScrolled = false

        if targetIndex <= 0 {
            targetIndex = 0
        } else {
            // in case you want to make page to center of View
            // by substract width with this additionalWidth
            additionalWidth = 20
        }

        if targetIndex > maxIndex {
            targetIndex = maxIndex
            isOverScrolled = true
        }

        let velocityX = velocity.x
        var newOffset = CGPoint(x: (CGFloat(targetIndex) * (self.pageWidth + self.spacingWidth)) - additionalWidth, y: 0)
        if velocityX == 0 {
            // when velocityX is 0, the jumping animation will occured
            // if we don't set targetContentOffset.pointee to new offset
            if !isOverScrolled &&  targetIndex == maxIndex {
                newOffset.x = scrollView.contentSize.width - scrollView.frame.width
            }
            targetContentOffset.pointee = newOffset
        }

        // Damping equal 1 => no oscillations => decay animation:
        UIView.animate(
            withDuration: 0.3, delay: 0,
            usingSpringWithDamping: 1,
            initialSpringVelocity: velocityX,
            options: .allowUserInteraction,
            animations: {
                scrollView.contentOffset = newOffset
                scrollView.layoutIfNeeded()
        }, completion: nil)
    }
}