滚动视图(UIScrollView) 其实是一个能够实现存放大图片以及实现滚动的组件,比如有的图片很大,但是用UIImageView装不下,那么这个时候就需要UIScrollView了,如果说举例子的话,很多地方都用到了,比如页面滚动的广告视图,滚动的头条等,那么它是一种什么效果呢,相信看完图之后立马就会明白了,因为这个程序非常简单,重点在于如何应用 滚动视图(UIScrollView),以及能够实现自动滚动的同时实现循环滚动。
该demo是比较早的时候写的,所以没有遵守MVC架构以及也没有屏幕适配,如果想达到比较好的效果,请适配4s或者5(s)的宽为320的模拟器
如果说用到UIScrollView(滚动视图),首先必须要明白的就是两个属性,一个叫做ContentOffSet(当前可见视图的左上角 在 背后屏幕视图 的坐标,俗称偏移量),另一个叫做ContentSize(背景屏幕视图 的大小),它之所以能够滚动,不是因为他只有一个滚动的属性,而是他的背后视图更大,一个视图显示不过来,所以才会出现能够移动,要想移动或者滚动,必须要设置ContentSize,解释如图
接着说一下,能够实现循环滚动的实现方法,实际是在第一张 以及最后一张 放置一张图,第一张的图和倒数第二张图(目测的最后一张图)是一样的,倒数第一张的图和第二张图(目测的第一张图)是一样的,实现用下面的图解释,红色的框为ScrollView的边框
当滚到右边数第二张图片的时候,下一次做滚动的时候就是最右侧的一张,利用时间差,不用动画效果,立马跳到第二张,因为是一样的,所以人的眼睛是感觉不出来的,第一张的切换是一样的。也就是说,如果想实现三张图片的循环滚动的话,就需要5个视图来当做背后视图
首先需要在延展中定义几个组件,如下
UIScrollView:滚动视图的前端(用以展示视图)
UILabel:用于显示滚动视图下侧的测试文字(如:RunIntoLove1)
UIPageControl:用于展示当前的页数小圆点,比如下面的三个白色的小圆点
NSTimer:定时器,用于相隔时间段调用切换图片的方法
// // ViewController.m // ScrollView 实现无限滚动 // // Created by YueWen on 15/8/25. // Copyright (c) 2015年 YueWen. All rights reserved. // #import "ViewController.h" #define COUNT 3//当前展示的视图的个数 @interface ViewController ()<UIScrollViewDelegate> @property(nonatomic,strong)UIScrollView * scrollView;//滚动视图 @property(nonatomic,strong)UILabel * label;//显示测试的视图 @property(nonatomic,strong)UIPageControl * pageControl;//页面控制器 @property(nonatomic,strong)NSMutableArray * items;//存取图片的数组 @property(nonatomic,strong)NSTimer * timer;//计时器 -(void)changeImage;//切换图片的方法 @end
首先加载在属性存储数据的数组items,每隔元素为一个字典,里面分别存图片的名字以及label显示的文字,因为比较复杂,so,打包成了一个方法,只需要在方法中调用即可,[self loadData],如下
/** * 加载存放label数据和图片的数组 */ -(void)loadData { self.items = [NSMutableArray array]; //将最后一张添加到第一张的前方 NSString * picName1 = [NSString stringWithFormat:@"%d.png",COUNT - 1]; UIImage * image1 = [UIImage imageNamed:picName1]; NSDictionary * dic1 = @{@"image":image1}; [self.items addObject:dic1]; for (int i = 0; i < COUNT; i++) { //获取图片 NSString * picName = [NSString stringWithFormat:@"%d.png",i]; UIImage * image = [UIImage imageNamed:picName]; //组建字典 NSString * s = [NSString stringWithFormat:@"RunIntoLove %d",i]; NSDictionary * dic = @{@"image":image,@"title":s}; //加入数组 [self.items addObject:dic]; } //将第一张添加到最后一张的后方 NSString * picName2 = [NSString stringWithFormat:@"%d.png",0]; UIImage * image2 = [UIImage imageNamed:picName2]; NSDictionary * dic2 = @{@"image":image2}; [self.items addObject:dic2]; }
//初始化横向滚动视图 self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 80, 320, 160)];//距离顶端80,宽为320,高为160 self.scrollView.backgroundColor = [UIColor blackColor];//背景颜色,只为测试,没有实际意义,运行时会被图片盖住 self.scrollView.delegate = self;//设置代理 [self.scrollView setContentOffset:CGPointMake(320, 0)];//将起始点定义到第二张图 [self.view addSubview:self.scrollView];//在父视图上添加
//初始化显示文字的label self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, 320, 40)]; self.label.text = [self.items[1] objectForKey:@"title"]; self.label.textAlignment = NSTextAlignmentCenter;//文字居中 self.label.backgroundColor = [UIColor blackColor]; self.label.textColor = [UIColor whiteColor]; self.label.alpha = 0.6;//透明度 [self.view addSubview:self.label];
//初始化pageControl self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 210, 320, 40)]; self.pageControl.numberOfPages = self.items.count - 2;//页码控制器的数量是 图片数 - 2(最前和最后的重复的) self.pageControl.currentPage = 0;//初始化当前的页码为0(与数组小标很类似,以0为开始) [self.view addSubview:self.pageControl];
/** * 加载scollView的方法 * 将self.items中的图片加到scollView中 */ -(void)loadScollView { for (int i = 0; i < self.items.count; i++) { UIImageView * view = [[UIImageView alloc] initWithFrame:CGRectMake(i * 320, 0, 320, 160)]; view.image = [self.items[i] objectForKey:@"image"]; [self.scrollView addSubview:view]; } }
[self.scrollView setContentSize:CGSizeMake(320 * self.items.count, 160)];//设置背景视图的大小,高为160,宽为图片张数 * 320(每张图片的宽度) self.scrollView.pagingEnabled = YES;//有分页效果
//初始化timer,用这个方法初始化计时器不需要手动启动计时器,如果用init需要手动启动 self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(changeImage) userInfo:nil repeats:YES];//表示每隔两秒调用一下 自身的 changeImage 方法,重复调用
/** * 定时器调用的滑动图的方法 */ -(void)changeImage { //获得当先scrollView滚动到的点(俗称偏移量) CGFloat offSetX = self.scrollView.contentOffset.x;//获取当前滚动视图的contentOffSet的x值 //让scrollView向右滚动一个屏幕宽的距离 offSetX += self.scrollView.bounds.size.width; [self.scrollView setContentOffset:CGPointMake(offSetX, 0) animated:YES];//开始偏移并伴有动画效果 }
实现页码切换的时候自然是在以下方法中,相信注释也比较清楚了,但是方法不唯一,楼主只是用的其中一种
/** * 滚动视图滚动的时候的委托回调方法 * * @param scrollView 滚动的视图 */ -(void)scrollViewDidScroll:(UIScrollView *)scrollView { //获得偏移量 CGPoint point = self.scrollView.contentOffset; //获得当前的最大x值(在可见区域内,最大的x轴上的值) CGFloat manX = self.scrollView.bounds.size.width * (self.items.count - 1); //如果当前点已经到了最前边的一张,即坐标为0,0 if (point.x == 0) { CGFloat x = self.scrollView.bounds.size.width * (self.items.count - 2); [self.scrollView setContentOffset:CGPointMake(x , 0)];//立马跳到倒数第二张(因为最后一张是为了往后滚动做的铺垫视图) } //如果当前点已经达到最后一张图,即坐标为 else if (point.x == manX) { [self.scrollView setContentOffset:CGPointMake(self.scrollView.bounds.size.width, 0)];//立马跳到整数第二张,第一张同理,利用人的视觉差 } //设置pageControl的点数 int pageNumber = [self imageIndexWithContentOffset:scrollView.contentOffset];//自定义方法,根据偏移量设置当前页码 self.pageControl.currentPage = pageNumber; //改变标签 int index = pageNumber + 1; self.label.text = [self.items[index] objectForKey:@"title"]; }
/** * 获取当前属于第几页,用于改变pageControl * * @param contentOffSet scrollView的左上角的点 * * @return 返回属于第几张 */ -(int)imageIndexWithContentOffset:(CGPoint)contentOffSet { return (contentOffSet.x - self.scrollView.bounds.size.width) / 320; }
/** * 滚动视图将要开始拖动滚动的时候的委托回调方法(自动调用偏移的时候不会回调这个方法,需外力作用,下面依旧是) * * @param scrollView 将要开始的滚动视图 */ -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self.timer invalidate];//取消计时器 self.timer = nil;//避免野指针 }
/** * 滚动视图拖动滚动结束时候的委托回调方法(手拖动离开屏幕的时候) * * @param scrollView 停止的滚动视图 * @param decelerate 是否减速 */ -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(changeImage) userInfo:nil repeats:YES]; }
另一种方法就是通过位置不断的变换位置,在这里不做说明,可以去github下载一下楼主的小demo研究一下
objc版
https://github.com/YRunIntoLove/Carousel-objc
swift版
https://github.com/YRunIntoLove/YWCarousel