UIScrollView学习

转自:http://www.cnblogs.com/kenshincui/p/3913885.html#UIScrollView

UIScrollView

通过上面的介绍相信大家对于UIView的基本操作应该比较熟悉了,那么下面就看一下UIView的子控件UIScrollView 。顾名思义,这是一个可以处理滚动操作的视图,UIScrollView在开发过程中使用很频繁,而且它也经常作为其他控件的子控件,例如UITableView就继承自UIScrollView。 我们还是先看一下UIScrollView的常用属性和方法: 
属性 说明
@property(nonatomic)         CGPoint                      contentOffset; 内容偏移量,当前显示的内容的顶点相对此控件顶点的x、y距离,默认为CGPointZero
@property(nonatomic)         CGSize                       contentSize; 控件内容大小,不一定在显示区域,如果这个属性不设置,此控件无法滚动,默认为CGSizeZero
@property(nonatomic)         UIEdgeInsets                 contentInset; 控件四周边距,类似于css中的margin,注意边距不作为其内容的一部分,默认为UIEdgeInsetsZero
@property(nonatomic,assign) id<UIScrollViewDelegate>      delegate; 控件代理,一般用于事件监听,在iOS中多数控件都是通过代理进行事件监听的
@property(nonatomic)         BOOL                         bounces; 是否启用弹簧效果,启用弹簧效果后拖动到边缘可以看到内容后面的背景,默认为YES
@property(nonatomic,getter=isPagingEnabled) BOOL          pagingEnabled; 是否分页,如果分页的话每次左右拖动则移动宽度是屏幕宽度整数倍,默认为NO
@property(nonatomic,getter=isScrollEnabled) BOOL          scrollEnabled;    是否启用滚动,默认为YES
@property(nonatomic)         BOOL                         showsHorizontalScrollIndicator; 是否显示横向滚动条,默认为YES
@property(nonatomic)         BOOL                         showsVerticalScrollIndicator; 是否显示纵向滚动条,默认为YES
@property(nonatomic) CGFloat minimumZoomScale; 最小缩放倍数,默认为1.0
@property(nonatomic) CGFloat maximumZoomScale; 最大缩放倍数(注意只有maximumZoomScale大于minimumZoomScale才有可能缩放),默认为1.0
@property(nonatomic,readonly,getter=isTracking)     BOOL tracking; (状态)是否正在被追踪,手指按下去并且还没有拖动时是YES,其他情况均为NO
@property(nonatomic,readonly,getter=isDragging)     BOOL dragging; 是否正在被拖拽
@property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating; 是否正在减速
@property(nonatomic,readonly,getter=isZooming)       BOOL zooming; 是否正在缩放
方法 说明
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; 设置滚动位置,第二个参数表示是否启用动画效果
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated; 滚动并显示指定区域的内容,第二个参数表示是否启用动画效果
代理方法 说明
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; 滚动事件方法,滚动过程中会一直循环执行(滚动中…)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; 开始拖拽事件方法
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 拖拽操作完成事件方法
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView; 即将停止滚动事件方法(拖拽松开后开始减速时执行)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;  滚动停止事件方法(滚动过程中减速停止后执行)
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view NS_AVAILABLE_IOS(3_2);  开始缩放事件方法
- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2); 缩放操作完成事件方法
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;  返回缩放视图,注意只有实现这个代理方法才能进行缩放,此方法返回需要缩放的视图

contentSize、contentInset、contentOffset在开发中会经常使用,为了帮助大家理解这里以图形的形式展现三者之间的关系:

UIScrollViewLayout

关于上面列出的几个方法,我们有必要说一下它们的执行顺序:

a.如果我们拖动一个UIScrollView中的子控件移动的时候它的执行顺序如下:开始拖拽,滚动,滚动…,停止拖拽,将要停止滚动,滚动,滚动…,停止滚动

红色部分有可能执行也有可能不执行,关键看你拖拽的停止的时候是突然停止还是有一段惯性让他继续执行(就好像刹车一样,如果是急刹车就没有后面的惯性滑动了,如果是慢慢踩刹车可能会有一段滑动距离)。但是不管怎么样滚动事件会一直执行,因此如果在这个事件中进行某种操作一定要注意性能。

b.如果我们缩放UIScrollView的子控件的时候它的执行顺序如下:开始缩放,滚动,滚动…,停止缩放。同样在这个过程中滚动事件会一直调用(当然如果缩放过程中手指有别的动作也可能会触发其他事件,这个大家可以自己体会一下)。

下面我们简单做一个例子

KCScrollViewController.h

//
//  KCScrollViewController.h
//  UIViewAndUIScrollView
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface KCScrollViewController : UIViewController

@property (nonatomic,strong) UIScrollView *scrollView;

@property (nonatomic,strong) UIImageView *imageView;

@end

KCScrollViewController.m

//
//  KCScrollViewController.m
//  UIViewAndUIScrollView
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCScrollViewController.h"

//实现UIScrollView代理
@interface KCScrollViewController ()<UIScrollViewDelegate>

@end

@implementation KCScrollViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //添加scrollView控件
    //注意UIScreen代表当前屏幕对象,其applicationFrame是当前屏幕内容区域
    _scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
    //_scrollView.backgroundColor=[UIColor redColor];
    _scrollView.contentMode=UIViewContentModeScaleToFill;
    [self.view addSubview:_scrollView];
    
    
    //添加图片控件
    UIImage *image=[UIImage imageNamed:@"wwdc14-labs-hero-background.jpg"];
    _imageView=[[UIImageView alloc]initWithImage:image];
    [_scrollView addSubview:_imageView];
    
    
    
    //contentSize必须设置,否则无法滚动,当前设置为图片大小
    _scrollView.contentSize=_imageView.frame.size;
    
    //实现缩放:maxinumZoomScale必须大于minimumZoomScale同时实现viewForZoomingInScrollView方法
    _scrollView.minimumZoomScale=0.6;
    _scrollView.maximumZoomScale=3.0;
    //设置代理
    _scrollView.delegate=self;
    

    //边距,不属于内容部分,内容坐标(0,0)指的是内容的左上角不包括边界
    //_scrollView.contentInset=UIEdgeInsetsMake(10, 20, 10, 20);
    
    //显示滚动内容的指定位置
    //_scrollView.contentOffset=CGPointMake(10, 0);
    
    //隐藏滚动条
    _scrollView.showsHorizontalScrollIndicator=NO;
    _scrollView.showsVerticalScrollIndicator=NO;
    
    //禁用弹簧效果
    //_scrollView.bounces=NO;
}

#pragma mark 实现缩放视图代理方法,不实现此方法无法缩放
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return _imageView;
}
-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
    NSLog(@"scrollViewWillBeginDecelerating");
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    NSLog(@"scrollViewDidEndDecelerating");
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    NSLog(@"scrollViewWillBeginDragging");
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    NSLog(@"scrollViewDidEndDragging");
}
-(void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view{
    NSLog(@"scrollViewWillBeginZooming");
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale{
    NSLog(@"scrollViewDidEndZooming");
}
//-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//    NSLog(@"scrollViewDidScroll");
//}

#pragma mark 当图片小于屏幕宽高时缩放后让图片显示到屏幕中间
-(void)scrollViewDidZoom:(UIScrollView *)scrollView{
    CGSize originalSize=_scrollView.bounds.size;
    CGSize contentSize=_scrollView.contentSize;
    CGFloat offsetX=originalSize.width>contentSize.width?(originalSize.width-contentSize.width)/2:0;
    CGFloat offsetY=originalSize.height>contentSize.height?(originalSize.height-contentSize.height)/2:0;

    _imageView.center=CGPointMake(contentSize.width/2+offsetX, contentSize.height/2+offsetY);
}

@end

运行效果如下:

scroll

默认情况下缩放后的内容会放到UIScrollView的内容起始位置,所以如果要想缩放后内容放到中间我们必须自己维护它的位置,上面已经给出了设置方法。

扩展—ARC

iOS5之后引入了ARC特性,程序中不用自己retain、release、autorelease操作,编译器会自动为你管理内存,编译时自动加上内存释放的代码,使用起来很方便。ARC是编译器特性,而不是iOS运行时特性,其实质还是手动管理内存,只是相应内存管理的代码编译器会自动生成而已。由于ARC是编译器特性,因此它管理内存的规则和之前ObjC内存管理是类似的,只要有一个对象引用(强引用)指向这个对象,那么这个对象就不会被释放。

在开启ARC之后我们可以使用四个关键字修饰我们的成员变量、局部变量和属性:

  • strong(修饰变量用__strong):强引用,相当于原来的retain,每次赋值引用计数器加1,只要指针引用这个对象,这个对象就不会被销毁; 
  • weak(修饰变量用__weak):弱引用,相当于assign,和assign不同的是当对象释放后该变量会设置为nil防止野指针(虽然之前讲过的内容中assign都是应用于基本数据类型,其实它也完全可以修饰对象类型的属性); 
  • unsafe_unretained(修饰变量用__unsafe_unretained):和weak类似,区别就是如果对象释放后它不会像weak一样自动将指针设置为nil,有可能出现野指针; 
  • __autoreleasing(只能修饰变量不能修饰属性):修饰一个对象在使用完之后自动释放,通常用于延迟释放内存,同在MRC下调用对象的autorelease方法是等效的;

注意:

  1. 除了weak(注意不是__weak)之外其他的修饰符在非ARC(MRC)下使用也不会报错,但是这么做并没有什么意义,因为在编译时会被忽略。举例来说:在MRC下使用__autoreleasing修饰一个对象也不会自动释放,而是应该使用autorelease方法。同样的,在MRC下使用__strong来修饰一个变量也同样是会直接忽略这个关键字;
  2. unsafe_unretained(或者__unsafe_unretained)和weak(或__weak)的区别不大,只是weak(或__weak)做释放之后会将变量设置为nil避免野指针,之所以目前两个关键字还存在主要是因为后者在在iOS5.0及lion之后才出现,出于兼容性考虑,因此推荐使用weak或__weak;
  3. __autoreleasing主要用于函数参数是ObjC对象指针的情况下(也就是参数”NSObject **obj”类型,指针的指针),典型的应用就是NSError的使用。在这种情况下,经常需要在函数内部重新创建一个对象给传入的参数赋值(修改参数内容),如果使用__autorelesing参数编译器在处理内部函数时会使用自动释放池,即保证内部对象能够正常释放又可以修改外部变量。之所以很多时候使用NSError作为参数传递到一些方法中没有将变量声明为__autoreleasing是因为编译器已经自动做了处理(因此,如果考虑到性能推荐还是加上此参数);

strong和weak在iOS开发过程中经常使用,这里简单看一个例子(注意这两个参数仍然可以修饰属性,意义是完全一样的在此不再演示)

KCPerson.h

//
//  KCPerson.h
//  ARC
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface KCPerson : NSObject

@property (nonatomic,assign) int no;

@end

KCPerson.m

//
//  KCPerson.m
//  ARC
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCPerson.h"

@implementation KCPerson

-(NSString *)description{
    return [NSString stringWithFormat:@"no=%i",_no];
}

@end

main.m

//
//  main.m
//  ARC
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "KCPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //strong
        __strong KCPerson *person1=[[KCPerson alloc]init];
        __strong KCPerson *person2=person1;
        person1.no=1;
        NSLog(@"%@",person2); //结果:no=1
        person1=nil;
        NSLog(@"%@",person2); //结果:no=1
        
        
        //weak
        __strong KCPerson *person3=[[KCPerson alloc]init];
        __weak KCPerson *person4=person3;
        person3.no=3;
        NSLog(@"%@",person4); //结果:no=3
        person3=nil;
        NSLog(@"%@",person4); //结果:(null)

    }
    return 0;
}

由于person1和person2都指向一个对象并且都是强引用,因此当person1设置为nil时对象仍然不会释放,所以此时person2还是指向这个对象,可以正常输出;person3和它指向的对象是强引用,而person4是弱引用,因此当person3设置为nil后,对象没有了强引用就会释放,此时再打印person4自然就是null。为了说明strong和weak的使用,下面使用图形方式描绘上面的情况:

strong--person1和person2的关系

strong2

weak--person3和person4的关系

weak2

由此得出如下结论:

  1. 不管是怎么管理内存都是针对对象类型而言(无论是strong,weak都不能应用到基本数据类型),对于基本数据类型直接声明为assign就可以了,它不需要我们自己管理内存; 
  2. 所有的指针变量默认都是__strong类型,因此我们通常省略不写__strong; 
  3. 如果一个对象没有强引用之后即使存在弱引用它也会被释放,与此同时弱引用将被设置为nil;

回过头来我们看一下前面UIScrollView部分的几个属性都设置成了strong,如果设置成weak行不行呢?答案是否定的。如果我们设置成weak,Xcode首先就会给出提出“Assigning retained object to weak variable; object will be released after assignment”,就是说ObjC对象赋值给一个弱引用变量,赋值之后对象会立即被销毁。其实根据前面介绍的内容很容易理解,就拿上面的scrollView属性来说,如果设置为weak,当使用“_scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];”给这个变量赋值,根据前面的知识如果一个对象没有了强引用就会被销毁,赋值完成后运行时看到这个对象只有一个弱引用_scrollView自然就会销毁这个对象,因此如果运行上面的程序就达不到之前看到的效果了。

但是如果使用storyboard来设计界面的时候,我们会发现系统默认生成的属性就是weak,此时为什么不会销毁呢?那是因为它的顶层对象保持了一个强引用strong,因此这个对象不会被销毁。这样一来我们得出如下结论:

  1. 在iOS开发中使用strong、weak代替之前的retain、assign(基本类型使用assign); 
  2. 如果一个属性使用IBOutlet修饰(也就是此属性时strongboard中组件)那么使用weak; 
  3. 如果一个属性不是storyboard组件(一般纯代码编写界面时),使用strong;

UIScrollView实战

前面介绍了iOS中UIKit的一些简单知识,这里我们一起利用前面的知识做一个例子--图片无限循环滚动。在这个例子中我们需要解决如下两个问题:

如何无限循环?

我们知道在UIScrollView中如果放置其他控件后,只要设置contentSize之后这些图片就可以滚动。如果要让图片无限循环那么只有两种办法,一种是无限循环叠加图片,另一种就是如果最后一张图片浏览完立即显示第一张图片。很明显第一种方法是不现实的,我们考虑使用第二种方式。其实使用第二种方式实现原理比较简单,只要在图片前后各放一张图片即可(此时共有n+2个图片在UIScrollView中)。例如我们有5张图片,只要使用7个UIImageView依次存放:图片5,图片1,图片2,图片3,图片4,图片5,图片1。当从图片1滚动到图片5时由于最后一张是图片1就给用户一种无限循环的感觉,当这张图完全显示后我们迅速将UIScrollView的contentOffset设置到第二个UIImageView,也就是图片1,接着用户可以继续向后滚动。当然向前滚动原理完全一样,当滚动到第一张图片(图片5)就迅速设置UIScrollView的contentOffset显示第6张图(图片5)。为了方便说明请看下面的示意图(注意示意图由于宽度有限只描述了3张图片显示的情景):

loopScroll2

如何优化性能?

无限循环实现了,但是我们知道如果图片过多这些图片势必全部加载到内存,这是我们不愿意看到的,此时我们需要优化上面的方案。其实从上面的方案我们也可以看出端倪,我们完全没必要创建n+2个UIImageView,其实3个已经足够(事实上也可以用两个实现,大家不妨自己思考一下),只要一直保持显示中间的UIImageView,滚动时动态更改三个UIImageView的图片即可。例如三个UIImageView默认放图片5、图片1、图片2,当前显示中间的UIImageView,也就是图片1,。如果向后滚动那么就会显示图片2,当图片2显示完整后迅速重新设置三个UIImageView的内容为图片1、图片2、图片3,然后通过contentOffset设置显示中间的UIImageView,也就是图片2。继续向后看到图片3,当图片3滚动完成迅速重新设置3个UIImageView的内容为图片2、图片3、图片4,然后设置contentOffset显示中间的UIImageView,也就是图片3。当然,向前滚动原理完全一样,如此就给用户一种循环错觉,而且不占用过多内存。

下面给出具体的实现,在这个程序中除了UIscrollView我们还可以看到UIPageControl的使用,实现并不复杂。首先我们需要将图片信息存储到plist文件中(日后方便扩展),并且设置plist的key表示图片的名称,value代表对应的图片描述,这个描述我们需要展示在界面上方。具体内容如下:

imageInfo.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>0.jpg</key>
    <string>iphone 5s</string>
    <key>1.jpg</key>
    <string>iphone 5c</string>
    <key>2.jpg</key>
    <string>ipad min with retain</string>
    <key>3.jpg</key>
    <string>ipad air</string>
    <key>4.jpg</key>
    <string>ipod</string>
    <key>5.jpg</key>
    <string>ipod touch</string>
    <key>6.jpg</key>
    <string>mac book pro</string>
    <key>7.jpg</key>
    <string>mac book air</string>
    <key>8.jpg</key>
    <string>imac</string>
</dict>
</plist>

在程序中我们需要读取plist文件并加载对应的图片,这里我们将图片按顺序依次命名:0.jpg、1.jpg…8.jpg。我们的程序主要集中于自定义的KCMainViewController.m中,在这里我们声明1个UIScrollView和3个UIImageView用于显示图片,同时声明一个UILable显示图片描述信息,声明一个UIPageControl来显示当前图片页数,具体代码如下:

//
//  KCMainViewController.m
//  ImageViewer
//
//  Created by Kenshin Cui on 14-2-23.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h"
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 568
#define IMAGEVIEW_COUNT 3

@interface KCMainViewController ()<UIScrollViewDelegate>{
    UIScrollView *_scrollView;
    UIImageView *_leftImageView;
    UIImageView *_centerImageView;
    UIImageView *_rightImageView;
    UIPageControl *_pageControl;
    UILabel *_label;
    NSMutableDictionary *_imageData;//图片数据
    int _currentImageIndex;//当前图片索引
    int _imageCount;//图片总数
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //加载数据
    [self loadImageData];
    //添加滚动控件
    [self addScrollView];
    //添加图片控件
    [self addImageViews];
    //添加分页控件
    [self addPageControl];
    //添加图片信息描述控件
    [self addLabel];
    //加载默认图片
    [self setDefaultImage];
}

#pragma mark 加载图片数据
-(void)loadImageData{
    //读取程序包路径中的资源文件
    NSString *path=[[NSBundle mainBundle] pathForResource:@"imageInfo" ofType:@"plist"];
    _imageData=[NSMutableDictionary dictionaryWithContentsOfFile:path];
    _imageCount=(int)_imageData.count;
}

#pragma mark 添加控件
-(void)addScrollView{
    _scrollView=[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    [self.view addSubview:_scrollView];
    //设置代理
    _scrollView.delegate=self;
    //设置contentSize
    _scrollView.contentSize=CGSizeMake(IMAGEVIEW_COUNT*SCREEN_WIDTH, SCREEN_HEIGHT) ;
    //设置当前显示的位置为中间图片
    [_scrollView setContentOffset:CGPointMake(SCREEN_WIDTH, 0) animated:NO];
    //设置分页
    _scrollView.pagingEnabled=YES;
    //去掉滚动条
    _scrollView.showsHorizontalScrollIndicator=NO;
}

#pragma mark 添加图片三个控件
-(void)addImageViews{
    _leftImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    _leftImageView.contentMode=UIViewContentModeScaleAspectFit;
    [_scrollView addSubview:_leftImageView];
    _centerImageView=[[UIImageView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    _centerImageView.contentMode=UIViewContentModeScaleAspectFit;
    [_scrollView addSubview:_centerImageView];
    _rightImageView=[[UIImageView alloc]initWithFrame:CGRectMake(2*SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    _rightImageView.contentMode=UIViewContentModeScaleAspectFit;
    [_scrollView addSubview:_rightImageView];

}
#pragma mark 设置默认显示图片
-(void)setDefaultImage{
    //加载默认图片
    _leftImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",_imageCount-1]];
    _centerImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",0]];
    _rightImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",1]];
    _currentImageIndex=0;
    //设置当前页
    _pageControl.currentPage=_currentImageIndex;
    NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentImageIndex];
    _label.text=_imageData[imageName];
}

#pragma mark 添加分页控件
-(void)addPageControl{
    _pageControl=[[UIPageControl alloc]init];
    //注意此方法可以根据页数返回UIPageControl合适的大小
    CGSize size= [_pageControl sizeForNumberOfPages:_imageCount];
    _pageControl.bounds=CGRectMake(0, 0, size.width, size.height);
    _pageControl.center=CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT-100);
    //设置颜色
    _pageControl.pageIndicatorTintColor=[UIColor colorWithRed:193/255.0 green:219/255.0 blue:249/255.0 alpha:1];
    //设置当前页颜色
    _pageControl.currentPageIndicatorTintColor=[UIColor colorWithRed:0 green:150/255.0 blue:1 alpha:1];
    //设置总页数
    _pageControl.numberOfPages=_imageCount;
    
    [self.view addSubview:_pageControl];
}

#pragma mark 添加信息描述控件
-(void)addLabel{
    
    _label=[[UILabel alloc]initWithFrame:CGRectMake(0, 10, SCREEN_WIDTH,30)];
    _label.textAlignment=NSTextAlignmentCenter;
    _label.textColor=[UIColor colorWithRed:0 green:150/255.0 blue:1 alpha:1];

    [self.view addSubview:_label];
}

#pragma mark 滚动停止事件
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    //重新加载图片
    [self reloadImage];
    //移动到中间
    [_scrollView setContentOffset:CGPointMake(SCREEN_WIDTH, 0) animated:NO];
    //设置分页
    _pageControl.currentPage=_currentImageIndex;
    //设置描述
    NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentImageIndex];
    _label.text=_imageData[imageName];
}

#pragma mark 重新加载图片
-(void)reloadImage{
    int leftImageIndex,rightImageIndex;
    CGPoint offset=[_scrollView contentOffset];
    if (offset.x>SCREEN_WIDTH) { //向右滑动
        _currentImageIndex=(_currentImageIndex+1)%_imageCount;
    }else if(offset.x<SCREEN_WIDTH){ //向左滑动
        _currentImageIndex=(_currentImageIndex+_imageCount-1)%_imageCount;
    }
    //UIImageView *centerImageView=(UIImageView *)[_scrollView viewWithTag:2];
    _centerImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",_currentImageIndex]];
    
    //重新设置左右图片
    leftImageIndex=(_currentImageIndex+_imageCount-1)%_imageCount;
    rightImageIndex=(_currentImageIndex+1)%_imageCount;
    _leftImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",leftImageIndex]];
    _rightImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",rightImageIndex]];
}

@end

在上面的代码中需要提醒大家的是一定要谨慎在滚动时进行相关操作,前面我们说过滚动事件会循环执行十分消耗性能,因此如果能不在其中操作的话尽可能不要在这个方法中进行相关操作,例如在上面的代码中我们的核心逻辑主要集中在滚动停止事件中,这个事件在一次滚动操作中只需要执行一次。

运行效果:

loopScrollTuning


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值