上一篇已經介紹了UIScrollView的使用,並且簡單的寫了一個輪播圖的例子,但是上一篇中的輪播圖不能自動滾動,也不能循環輪播。今天有時間整理一下自動循環輪播的真正輪播圖實例。
循環輪播圖的原理
實現循環輪播的原理現在常用的有兩種:
1、創建n+2個滾動子視圖。在滾動到首尾時候進行轉換調整。
2、創建3個滾動子視圖,每次滾動結束進行圖片位置調整。
本實例代碼使用第二種方式,創建3個滾動子視圖。
廢話不多說,直接上代碼,在代碼中做了詳細的註釋。
自定義類CustomerView.h文件代碼
#import <UIKit/UIKit.h>
//聲明協議,給輪播圖的點擊添加一個代理
//這裏使用@class是因爲下面的代理方法需要使用到本類。
@class CustomerView;
@protocol CustomerViewDelegate<NSObject>
@optional
//代理方法 點擊圖片回調
- (void)customerView:(CustomerView *)view indexOfClickedImage:(NSInteger)index;
@end
@interface CustomerView : UIView
//傳入用於輪播圖的圖片數組
@property (nonatomic, copy)NSArray *images;
//pageControl顏色設置
@property (nonatomic, strong) UIColor *currentPageColor;
@property (nonatomic, strong) UIColor *pageColor;
//代理
@property (nonatomic, weak) id<CustomerViewDelegate> delegate;
@end
自定義類CustomerView.m文件代碼
#import "CustomerView.h"
//輪播圖創建的圖片數量
static const int imageCount = 3;
//準守UIScrollViewDelegate協議
@interface CustomerView ()<UIScrollViewDelegate>
//定義全局變量在後面的自動輪播方法中使用
@property (nonatomic, weak)UIScrollView *scrollView;
@property (nonatomic, weak)UIPageControl *pageControl;
//定時器,用於自動輪播
@property (nonatomic, weak)NSTimer *timer;
@end
@implementation CustomerView
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
//定義一個scrollView,最主要的輪播控件
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.delegate = self;
//橫豎兩種滾輪都不顯示
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
//需要分頁
scrollView.pagingEnabled = YES;
//不需要回彈
scrollView.bounces = NO;
[self addSubview:scrollView];
self.scrollView = scrollView;
//在scrollView中添加三個圖片
for (int i = 0;i < imageCount; i++) {
UIImageView *imageView = [[UIImageView alloc] init];
[scrollView addSubview:imageView];
}
//添加pageControl
UIPageControl *pageControl = [[UIPageControl alloc] init];
[self addSubview:pageControl];
self.pageControl = pageControl;
}
return self;
}
//佈局子控件
- (void)layoutSubviews {
[super layoutSubviews];
//設置scrollView的frame
self.scrollView.frame = self.bounds;
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
//設置contentSize,不同輪播方向的時候contentSize是不一樣的
//contentSize要放三張圖片
self.scrollView.contentSize = CGSizeMake(width * imageCount, height);
//設置三張圖片的位置,併爲三個圖片添加點擊事件
for (int i = 0; i < imageCount; i++) {
UIImageView *imageView = self.scrollView.subviews[i];
//給圖片添加點擊手勢
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewClick:)];
[imageView addGestureRecognizer:tap];
//設置圖片大小,和View相同
imageView.frame = CGRectMake(i * width, 0, width, height);
}
//設置contentOffset,顯示最中間的圖片
self.scrollView.contentOffset = CGPointMake(width, 0);
//設置pageControl的位置
CGFloat pageW = 100;
CGFloat pageH = 20;
CGFloat pageX = width/2-50;
CGFloat pageY = height - pageH;
self.pageControl.frame = CGRectMake(pageX, pageY, pageW, pageH);
}
//設置pageControl的CurrentPageColor
- (void)setCurrentPageColor:(UIColor *)currentPageColor {
_currentPageColor = currentPageColor;
self.pageControl.currentPageIndicatorTintColor = currentPageColor;
}
//設置pageControl的pageColor
- (void)setPageColor:(UIColor *)pageColor {
_pageColor = pageColor;
self.pageControl.pageIndicatorTintColor = pageColor;
}
//根據傳入的圖片數組設置圖片
- (void)setImages:(NSArray *)images {
_images = images;
//pageControl的頁數就是圖片的個數
self.pageControl.numberOfPages = images.count;
//默認一開始顯示的是第0頁
self.pageControl.currentPage = 0;
//設置圖片顯示內容
[self setContent];
//開啓定時器
[self startTimer];
}
//設置顯示內容
- (void)setContent {
//設置三個imageBtn的顯示圖片
for (int i = 0; i < self.scrollView.subviews.count; i++) {
//取出三個imageView
UIImageView *imageView = self.scrollView.subviews[i];
//這個是爲了給圖片做索引用的
NSInteger index = self.pageControl.currentPage;
if (i == 0) { //第一個imageView,隱藏在當前顯示的imageView的左側
index--; //當前頁索引減1就是第一個imageView的圖片索引
} else if (i == 2) { //第三個imageView,隱藏在當前顯示的imageView的右側
index++; //當前頁索引加1就是第三個imageView的圖片索引
}
//無限循環效果的處理就在這裏
if (index < 0) { //當上面index爲0的時候,再向右拖動,左側圖片顯示,這時候我們讓他顯示最後一張圖片
index = self.pageControl.numberOfPages - 1;
} else if (index == self.pageControl.numberOfPages) { //當上面的index超過最大page索引的時候,也就是滑到最右再繼續滑的時候,讓他顯示第一張圖片
index = 0;
}
imageView.tag = index;
//用上面處理好的索引給imageView設置圖片
imageView.image = self.images[index];
}
}
//狀態改變之後更新顯示內容
- (void)updateContent {
CGFloat width = self.bounds.size.width;
[self setContent];
//唯一跟設置顯示內容不同的就是重新設置偏移量,讓它永遠用中間的按鈕顯示圖片,滑動之後就偷偷的把偏移位置設置回去,這樣就實現了永遠用中間的按鈕顯示圖片
//設置偏移量在中間
self.scrollView.contentOffset = CGPointMake(width, 0);
}
#pragma mark - UIScrollViewDelegate
//拖拽的時候執行哪些操作
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
//拖動的時候,哪張圖片最靠中間,也就是偏移量最小,就滑到哪頁
//用來設置當前頁
NSInteger page = 0;
//用來拿最小偏移量
CGFloat minDistance = MAXFLOAT;
//遍歷三個imageView,看那個圖片偏移最小,也就是最靠中間
for (int i = 0; i < self.scrollView.subviews.count; i++) {
UIImageView *imageView = self.scrollView.subviews[i];
CGFloat distance = 0;
distance = ABS(imageView.frame.origin.x - scrollView.contentOffset.x);
if (distance < minDistance) {
minDistance = distance;
page = imageView.tag;
}
}
self.pageControl.currentPage = page;
}
//開始拖拽的時候停止計時器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self stopTimer];
}
//結束拖拽的時候開始定時器
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
[self startTimer];
}
//結束拖拽的時候更新image內容
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self updateContent];
}
//scroll滾動動畫結束的時候更新image內容
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[self updateContent];
}
#pragma mark - 定時器
//開始計時器
- (void)startTimer {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
self.timer = timer;
}
//停止計時器
- (void)stopTimer {
//結束計時
[self.timer invalidate];
//計時器被系統強引用,必須手動釋放
self.timer = nil;
}
//通過改變contentOffset * 2換到下一張圖片
- (void)nextImage {
CGFloat width = self.bounds.size.width;
[self.scrollView setContentOffset:CGPointMake(2 * width, 0) animated:YES];
}
- (void)imageViewClick:(UITapGestureRecognizer *)tap {
// NSLog(@"%ld",btn.tag);
UIView *imageView = tap.view;
if ([self.delegate respondsToSelector:@selector(customerView:indexOfClickedImage:)])
{
[self.delegate customerView:self indexOfClickedImage:imageView.tag];
}
}
@end
ViewController中調用代碼
#import "ViewController.h"
#import "CustomerView.h"
//遵守協議
@interface ViewController ()<CustomerViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//創建視圖
CustomerView *customerView = [[CustomerView alloc] initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, 300)];
//設置代理
customerView.delegate = self;
//圖片數組賦值
customerView.images = @[
[UIImage imageNamed:@"image_0.jpg"],
[UIImage imageNamed:@"image_1.jpg"],
[UIImage imageNamed:@"image_2.jpg"],
[UIImage imageNamed:@"image_3.jpg"]
];
customerView.currentPageColor = [UIColor whiteColor];
customerView.pageColor = [UIColor blueColor];
[self.view addSubview:customerView];
}
#pragma mark--CustomerViewDelegate 實現代理方法
- (void)customerView:(CustomerView *)view indexOfClickedImage:(NSInteger)index{
NSLog(@"點擊了第%ld張圖片",index);
}
@end
全部代碼都已經貼出來了,就不再上傳demo了。