ios - 轮播图手动无限滑动(2)

使用UIScrollView+NSTimer制作

方法解决了从UIScrollView手动滑动无法无线循环的问题。

方法说明

1、循环图片要比原来的多两个:在原来的数组的开头增加数组最后一个图片,在末尾增加数组最前面的一张图片。
2、设置一个计数器,记录当前偏移量的变量。数组由零开始,需要将数组起始位置调到1。
3、图片往右边移动:如果当前位置大于移动前的偏移量,则视为视图往右边滑动
4、图片往左边移动:如果当前位置小于移动前的偏移量,则视为视图往右边滑动

代码部分

定义全局变量
页数需要自己定义

@property (nonatomic, strong) UIScrollView *scrollView;    // 主滑动view
@property (nonatomic, strong) UIPageControl *pageControl;  // 分页控件
@property (nonatomic, strong) NSTimer *kvTimer;            // 定时器
@property (nonatomic, assign) NSInteger pageCount;         // 页数
@property (nonatomic, assign) CGFloat preOffsetX;		   //手动退拽时保存前的偏移量,便于判断方向

当页面手动滑动或者加载完成就开启定时器

self.kvTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(changePageLeft) userInfo:nil repeats:YES];

使用懒加载加载控件,首先定义UIScrollView,在定义的过程中将页数放入其中
注意将需要滑动展示的图片个数添加到scrollView中
注意[self.datasource carouselView:self cellAtIndex:_pageCount - 1],此处可以用来添加需要在pageView中需要添加的其他样式视图,最后在UIControl视图中显示。需要自己定义方便调用。

- (UIScrollView *)scrollView
{
    if (!_scrollView)
    {
        // 初始化尺寸
        _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        // 设置分页效果
        _scrollView.pagingEnabled = YES;
        // 水平滚动条隐藏
        _scrollView.showsHorizontalScrollIndicator = NO;
        // 设置到边的弹性隐藏
        _scrollView.bounces = NO;
        // 设置分页数
        self.pageCount = [self.datasource countOfCellForCarouseView:self];
        // 设置滚动范围
        _scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame) * (_pageCount + 2), CGRectGetHeight(self.frame));
        // 设置代理
        _scrollView.delegate = self;
        
        // 添加分页,左右增加一页
        for (int i = 0; i < _pageCount + 2; i++)
        {
            // 添加control,设置偏移位置
            UIControl *control = [[UIControl alloc] initWithFrame:CGRectMake(self.frame.size.width * i, 0, self.frame.size.width, self.frame.size.height)];
            UIView *pageView = nil;
            if (i == 0)
            {
                // 第一页多余页跟最后一页一样并重新定义
                pageView = [self.datasource carouselView:self cellAtIndex:_pageCount - 1];
            }
            else if (i == _pageCount + 1)
            {
                // 最后多余的一页跟第一页一样并重新定义
                pageView = [self.datasource carouselView:self cellAtIndex:0];
            }
            else
            {
                pageView = [self.datasource carouselView:self cellAtIndex:i - 1];
            }
            // 添加pageview
            pageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
            // 将pageview挂在control上
            [control addSubview:pageView];
            // 为每个页面添加响应层
            [control addTarget:self action:@selector(pageCliked) forControlEvents:UIControlEventTouchUpInside];
            [_scrollView addSubview:control];
        }
    }
    return _scrollView;
}

在创建UIPageControl控件

- (UIPageControl *)pageControl
{
    if (!_pageControl)
    {
        // 设置尺寸,坐标,注意纵坐标的起点
        _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 50, self.frame.size.width, 50)];
        // 设置页面数
        _pageControl.numberOfPages = _pageCount;
        // 设置当前页面索引
        _pageControl.currentPage = 0;
        // 设置未被选中时小圆点颜色
        _pageControl.pageIndicatorTintColor = [UIColor whiteColor];
        // 设置被选中时小圆点颜色
        _pageControl.currentPageIndicatorTintColor = [UIColor greenColor];
        // 设置能手动点小圆点条改变页数
        _pageControl.enabled = YES ;
        // 把导航条设置为半透明状态
        [_pageControl setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:0.2]];
        // 设置分页控制器的事件
        [_pageControl addTarget:self action:@selector(pageControlTouched) forControlEvents:UIControlEventValueChanged];
    }
    return _pageControl;
}

pagecontrol事件

// 这个是点击小圆点条进行切换,到边不能循环
- (void)pageControlTouched
{
    // 点击的时候停止计时
    [self.kvTimer setFireDate:[NSDate distantFuture]];
    
    // 滑到指定页面
    NSInteger curPageIdx = _pageControl.currentPage;
    CGFloat offsetX = self.frame.size.width * (curPageIdx + 1);
    [self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];

    // 重新开启定时器
    [self.kvTimer setFireDate:[NSDate dateWithTimeInterval:kTimerInterval sinceDate:[NSDate date]]];
}

UIScrollView协议书写

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//    printf("start drag\n");
    // 记录偏移量
    preOffsetX = scrollView.contentOffset.x;
    // 开始手动滑动时暂停定时器
    [self.kvTimer setFireDate:[NSDate distantFuture]];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//    printf("end drag\n");
    // 左右边界
    CGFloat leftEdgeOffsetX = 0;
    CGFloat rightEdgeOffsetX = self.frame.size.width * (_pageCount + 1);
    
    if (scrollView.contentOffset.x < preOffsetX)
    {
        // 左滑
        if (scrollView.contentOffset.x > leftEdgeOffsetX)
        {
            self.pageControl.currentPage = scrollView.contentOffset.x / self.frame.size.width - 1;
        }
        else if (scrollView.contentOffset.x == leftEdgeOffsetX)
        {
            self.pageControl.currentPage = _pageCount - 1;
        }
        if (scrollView.contentOffset.x == leftEdgeOffsetX)
        {
            self.scrollView.contentOffset = CGPointMake(self.frame.size.width * _pageCount, 0);
        }
    }
    else
    {
        // 右滑
        // 设置小点
        if (scrollView.contentOffset.x < rightEdgeOffsetX)
        {
            self.pageControl.currentPage = scrollView.contentOffset.x / self.frame.size.width - 1;
        }
        else if (scrollView.contentOffset.x == rightEdgeOffsetX)
        {
            self.pageControl.currentPage = 0;
        }
        // 滑动完了之后从最后多余页赶紧切换到第一页
        if (scrollView.contentOffset.x == rightEdgeOffsetX)
        {
            self.scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        }
    }
    // 结束后又开启定时器
    [self.kvTimer setFireDate:[NSDate dateWithTimeInterval:kTimerInterval sinceDate:[NSDate date]]];
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
//    printf("end scroll\n");
}

定时器控制事件

// 往右边滑
- (void)changePageRight
{
    // 设置当前需要偏移的量,每次递增一个page宽度
    CGFloat offsetX = _scrollView.contentOffset.x + CGRectGetWidth(self.frame);
    
    // 根据情况进行偏移
    CGFloat edgeOffsetX = self.frame.size.width * (_pageCount + 1);  // 最后一个多余页面右边缘偏移量
    
    // 从多余页往右边滑,赶紧先设置为第一页的位置
    if (offsetX > edgeOffsetX)
    {
        // 偏移量,不带动画,欺骗视觉
        self.scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        // 这里提前改变下一个要滑动到的位置为第二页
        offsetX = self.frame.size.width * 2;
    }
    
    // 带动画滑动到下一页面
    [self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
    if (offsetX < edgeOffsetX)
    {
        self.pageControl.currentPage = offsetX / self.frame.size.width - 1;
    }
    else if (offsetX == edgeOffsetX)
    {
        // 最后的多余那一页滑过去之后设置小点为第一个
        self.pageControl.currentPage = 0;
    }
}

// 往左边滑
- (void)changePageLeft
{
    // 设置当前需要偏移的量,每次递减一个page宽度
    CGFloat offsetX = _scrollView.contentOffset.x - CGRectGetWidth(self.frame);
    
    // 根据情况进行偏移
    CGFloat edgeOffsetX = 0;  // 最后一个多余页面左边缘偏移量
    
    // 从多余页往左边滑动,先设置为最后一页
    if (offsetX < edgeOffsetX)
    {
        self.scrollView.contentOffset = CGPointMake(self.frame.size.width * _pageCount, 0);
        offsetX = self.frame.size.width * (_pageCount - 1);
    }
    
    // 带动画滑动到前一页面
    [self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
    if (offsetX > edgeOffsetX)
    {
        self.pageControl.currentPage = offsetX / self.frame.size.width - 1;
    }
    else if (offsetX == edgeOffsetX)
    {
        // 最后的多余那一页滑过去之后设置小点为最后一个
        self.pageControl.currentPage = _pageCount - 1;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 `UICollectionView` 或 `UIPageViewController` 来实现 iOS 片轮。 使用 `UICollectionView` 实现的方法如下: 1. 在您的视控制器中,创建一个 `UICollectionView` 实例,并将其作为子视添加到您的视控制器的视中。 2. 使用自定义布局实现循环滚动。可以参考以下代码: ``` class LoopCollectionViewFlowLayout: UICollectionViewFlowLayout { override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { guard let collectionView = collectionView else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) } let collectionViewSize = collectionView.bounds.size let proposedContentOffsetCenterX = proposedContentOffset.x + collectionViewSize.width * 0.5 let proposedRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionViewSize.width, height: collectionViewSize.height) guard let layoutAttributes = layoutAttributesForElements(in: proposedRect) else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) } let centerX = proposedContentOffsetCenterX let offset = CGPoint(x: proposedContentOffset.x + nearestTargetOffset(for: layoutAttributes, with: centerX), y: proposedContentOffset.y) return offset } private func nearestTargetOffset(for layoutAttributes: [UICollectionViewLayoutAttributes], with centerX: CGFloat) -> CGFloat { let targetAttributes = layoutAttributes.sorted { abs($0.center.x - centerX) < abs($1.center.x - centerX) } let nearestAttribute = targetAttributes.first return nearestAttribute?.center.x ?? 0 - centerX } } ``` 3. 创建自定义 `UICollectionViewCell` 类,并在其中添加一个 `UIImageView` 用于显示片。 4. 实现 `UICollectionViewDataSource` 协议中的方法,用于设置片数据源和自定义的 `UICollectionViewCell`。 5. 实现定时器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值