• 【iOS开发-55】图片轮播案例:scrollView的分页、滚动栏、利用代理控制定时器和Page Control以及多线程问题


    案例:



    (1)用storyboard布局,这里用了三样东西。

    ——UIScrollView就是我们准备存放滚动图片的容器。

    ——Page Control就是控制页数的那几个小点点。能够设置有多少个点。当前点和其它点的颜色等。注意它和UIScrollView是平级的,不是它的子视图。

    ——另一个textView是带有滚动的,用来測试多线程的。

    暂且任意拖放在页面中就可以。


    (2)在ViewController.m中

    ——借助之前的scrollView属性,设置滚动范围

    ——借助新学习的scrollView的属性pagingEnabled直接设置scrollView是否分页。这里面须要注意的是,假设要借助这样的方式实现分页,那么最好让scrollView的宽度正好等于里面每张图片的宽度。否则分页会出现截断。

    由于分页是依照scrollView的宽度给整个滚动区域做分割的。

    ——借助showsHorizontalScrollIndicator属性去除水平滚动栏,垂直滚动栏的属性。输入showsVe....查看。这里略去。

    ——借助定时器,实现每隔1秒钟播放下一张图片的效果。

    ——这里相同用到代理:

        由于我们须要监听scrollView滚动到哪里:以设置响应的Page Control的当前点点。

        由于我们须要监听scrollView是否被拖拽。假设被拖拽。那么就停止那个定时器。

        由于我们须要监听scrollView是否停止被拖拽,假设不被拖拽,那么要又一次加入一个定时器。

    ——当然,这里面定时器每隔1秒播放下一张图片,事实上是定时器每隔1秒运行一次imagePlay方法,这个imagePlay方法主要通过改变scrollView的contentOffset值来实现scrollView的滚动。

    #import "ViewController.h"
    
    @interface ViewController ()<UIScrollViewDelegate>
    @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
    @property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
    @property (strong,nonatomic) NSTimer *timer;
    
    @end
    
    @implementation ViewController
    //总共图片数量
    #define kIMGCOUNT 5
    
    - (void)viewDidLoad {
        CGFloat imageY=0;
        CGFloat imageW=self.scrollView.frame.size.width;
        CGFloat imageH=self.scrollView.frame.size.height;
        //用for循环往ScrollView中加入图片,这里面计算每张图片的x值是重点
        for (int i=0; i<kIMGCOUNT; i++) {
            UIImageView *imageView=[[UIImageView alloc]init];
            CGFloat imageX=i*imageW;
            imageView.frame=CGRectMake(imageX, imageY, imageW, imageH);
            imageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d",i+1]];
            [self.scrollView addSubview:imageView];
        }
        //然后设置scrollView的contentSize,这样才干滚动起来,这里滚动仅仅有横向滚动,所以竖向的为0
        self.scrollView.contentSize=CGSizeMake(kIMGCOUNT*imageW, 0);
        //分页,pagingEnabled是scrollView的一个属性
        self.scrollView.pagingEnabled=YES;
        //去除水平滚动栏
        self.scrollView.showsHorizontalScrollIndicator=NO;
        //设置页数控制器总页数,即button数
        self.pageControl.numberOfPages=kIMGCOUNT;
        
        //设置代理
        self.scrollView.delegate=self;
        
        //设置自己主动播放。定时器。每隔1秒钟播放下一张图片
        [self timerOn];
        
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    }
    //比方下一张图片,事实上就是拖动scrollView。也就是改变scrollView的contentOffset属性
    //当然。这里要推断一下,假设播放最后一张了,那么下一张就是第一张
    -(void)imgPlay{
        int i=self.pageControl.currentPage;
        if (i==kIMGCOUNT-1) {
            i=-1;
        }
        i++;
        [self.scrollView setContentOffset:CGPointMake(i*self.scrollView.frame.size.width, 0) animated:YES];
    }
    //当用户准备拖拽的时候。关闭定时器
    -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
        [self timerOff];
    }
    //当用户停止拖拽的时候,加入一个定时器
    -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
        [self timerOn];
    }
    //每隔1秒播放图片,事实上是每隔1秒调用imgPlay方法
    -(void)timerOn{
        self.timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(imgPlay) userInfo:nil repeats:YES];
        //为了防止单线程的弊端,能够保证用户在使用其它控件的时候系统照样能够让定时器运转
        [[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
    }
    //关闭定时器,而且把定时器设置为nil,这是习惯
    -(void)timerOff{
        [self.timer invalidate];
        self.timer=nil;
    }
    //这个事推断定时器滚动的时候,实时推断滚动位置。以让Page Controll显示当前的点是哪一个点
    //这个须要在总宽度上加上半个scrollView的宽度,是为了保证拖拽到一半时候左右的效果
    -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
        self.pageControl.currentPage=(self.scrollView.frame.size.width*0.5+self.scrollView.contentOffset.x)/self.scrollView.frame.size.width;
    }
    
    @end

    当然,这里面的代码是经过一些封装的。

    比方,我们把开关定时器封装成两个方法。这样哪里用到仅仅须要调用下面就可以。


    (3)Page Control。事实上就是一些小点点,你能够设置当前处于第几个点。一共同拥有几个点,当前点得颜色,其它点得颜色等等。


    (4)这里面涉及到了一个多线程的知识。

    一般我们值面向单线程,即系统每次仅仅能处理一个事件,比方我们这里的图片轮播,假设用户在页面上拖拽其它东西,比方我们这里的textView。那么系统就会集中处理这个事件。无暇顾及我们的图片轮播。所以这个时候图片轮播就不动了。

    我们要介绍的时NSRunLoop这个类。它是什么呢?事实上看了非常多他人的笔记,大家仅仅说了它的作用功能,可是连最主要的翻译都没有,翻看官方文档,我们能够把它理解成是一个专门用来接受用户一些输入操作的台子。一般而言,单线程的话。这个台子仅仅能接受一个操作。所以才会出现我们上面的情况。

    要解决问题的思路就在于:我们先拿到当前的台子 >>> 然后把我们的定时器死乞白赖地加入到这个台子里 >>> 相当于我们这个定时器也时时刻刻被系统处理着,不会由于其它事件而忽略定时器。

        [[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];

  • 相关阅读:
    《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(中)
    《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(上)
    《ASP.ENT Core 与 RESTful API 开发实战》-- (第4章)-- 读书笔记(下)
    《ASP.ENT Core 与 RESTful API 开发实战》-- (第4章)-- 读书笔记(上)
    《ASP.ENT Core 与 RESTful API 开发实战》(第3章)-- 读书笔记(下)
    《ASP.ENT Core 与 RESTful API 开发实战》(第3章)-- 读书笔记(中)
    《ASP.ENT Core 与 RESTful API 开发实战》(第3章)-- 读书笔记(上)
    《ASP.ENT Core 与 RESTful API 开发实战》-- 读书笔记(第2章)
    《ASP.ENT Core 与 RESTful API 开发实战》-- 读书笔记(第1章)
    ASP.NET Core分布式项目实战(集成ASP.NETCore Identity)--学习笔记
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8706812.html
Copyright © 2020-2023  润新知