滚动视图(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 ()
@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