現在很多app都有自動切換圖檔展示功能尤其是視訊播放器,電商app,今天我給大家開發一個這樣常用的元件,該控件是純手工打造,自己實作觸摸控制沒有用UIScrollView,下面是實作原理:建立三個UIImageView控件通過觸摸切換該種方式節省記憶體,當使用者要展示100張圖檔時也隻會建立三個UIImageView控件。
WHC_AdvertisingWall.h 頭檔案代碼如下:
//
// WHC_AdvertisingWall.h
// WHC_AdvertisingWall
//
// Created by 吳海超 on 15/3/24.
// Copyright (c) 2015年 吳海超. All rights reserved.
//
#import <UIKit/UIKit.h>
@class WHC_AdvertisingWall;
//單擊圖檔代理
@protocol WHC_AdvertisingWallDelegate <NSObject>
@optional
- (void)WHC_AdvertisingWall:(WHC_AdvertisingWall*)whc_AdWallView clickImage:(UIImage*)image index:(NSInteger)index;
@end
@interface WHC_AdvertisingWall : UIView
@property (nonatomic,assign) BOOL isCanTouchScroll;
@property (nonatomic,assign) BOOL isCanAutoScroll;
@property (nonatomic,assign) id<WHC_AdvertisingWallDelegate> delegate;
//以圖檔對象數組進行初始化
- (instancetype)initWithFrame:(CGRect)frame withImages:(NSArray*)imageArr;
-
//以圖檔名稱數組進行初始化
- (instancetype)initWithFrame:(CGRect)frame withImageNames:(NSArray *)imageNames;
-
//以圖檔對象重載圖檔
- (void)reloadImage:(NSArray*)images;
-
//以圖檔名稱重載圖檔
- (void)reloadImageNames:(NSArray*)imageNames;
@end
WHC_AdvertisingWall.m源檔案實作原理:
//
// WHC_AdvertisingWall.m
// WHC_AdvertisingWall
//
// Created by 吳海超 on 15/3/24.
// Copyright (c) 2015年 吳海超. All rights reserved.
//
#import "WHC_AdvertisingWall.h"
#define KWHC_MOVE_IMAGE_DURING (0.4) //動畫切換圖檔周期
#define KWHC_LEFT_START_INDEX (1) //向左切換時的初始imageView下标
#define KWHC_RIGHT_START_INDEX (0) //向右切換時的初始imageView下标
#define KWHC_PAGE_CONTROL_HEIGHT (20.0) //頁控件高度
//方向枚舉
typedef enum {
NONE,
LEFT,
RIGHT
}WHC_TOUCH_ORI;
@interface WHC_AdvertisingWall (){
NSArray * _imageArr; //圖檔數組
NSMutableArray * _imageViewArr; //圖檔控件數組
UIPageControl * _pageCtl; //頁控件
NSTimer * _timer; //定時器
UIPanGestureRecognizer * _panGesture; //觸摸手勢
CGRect _frame; //該控件frame
NSInteger _currentIndex; //目前圖檔下标
CGPoint _startPoint; //觸摸開始點
WHC_TOUCH_ORI _currentMoveOri; //目前移動方向
BOOL _isStartTouch; //是否開始觸摸了
}
@end
@implementation WHC_AdvertisingWall
#pragma mark - init
- (instancetype)initWithFrame:(CGRect)frame withImages:(NSArray*)imageArr{
self = [super initWithFrame:frame];
if(self != nil){
_currentIndex = ;
_currentMoveOri = NONE;
_frame = frame;
_imageArr = [NSArray arrayWithArray:imageArr];
_imageViewArr = [NSMutableArray array];
//注冊觸摸事件
[self registerTouchEvent];
//初始化ui布局
[self initLayout];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame withImageNames:(NSArray *)imageNames{
NSMutableArray * images = [NSMutableArray array];
for (NSString * imagePath in imageNames) {
[images addObject:[UIImage imageNamed:imagePath]];
}
return [self initWithFrame:frame withImages:images];
}
#pragma mark - controlAnimation
//設定是否可以觸摸切換
- (void)setIsCanTouchScroll:(BOOL)isCanTouchScroll{
_isCanTouchScroll = isCanTouchScroll;
if(!isCanTouchScroll){
[self removeGestureRecognizer:_panGesture];
}else{
[self addGestureRecognizer:_panGesture];
}
}
//設定是否可以自動切換
- (void)setIsCanAutoScroll:(BOOL)isCanAutoScroll{
_isCanAutoScroll = isCanAutoScroll;
if(isCanAutoScroll){
if(_timer != nil){
[_timer invalidate];
_timer = nil;
}
_timer = [NSTimer scheduledTimerWithTimeInterval: target:self selector:@selector(startAutoScrollImage) userInfo:nil repeats:YES];
}else{
[_timer invalidate];
_timer = nil;
}
}
//開始自動切換
- (void)startAutoScrollImage{
//default to left scroll image
[self animationMoveImage:KWHC_LEFT_START_INDEX withOri:LEFT];
}
#pragma mark - other
//加載錯誤提示view
- (void)loadAlertText{
UILabel * labText = [[UILabel alloc]initWithFrame:CGRectMake(, , CGRectGetWidth(_frame), CGRectGetHeight(_frame))];
labText.backgroundColor = [UIColor clearColor];
labText.textColor = [UIColor grayColor];
labText.textAlignment = NSTextAlignmentCenter;
labText.numberOfLines = ;
labText.text = @"WHC_AdvertisingWall\nimage count = 0";
[self addSubview:labText];
}
- (void)registerTouchEvent{
_panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
}
#pragma mark - reload
//重新載入圖檔(image對象)
- (void)reloadImage:(NSArray*)images{
for (UIView * view in self.subviews) {
[view removeFromSuperview];
}
self.isCanTouchScroll = NO;
self.isCanAutoScroll = NO;
_currentIndex = ;
_currentMoveOri = NONE;
[_imageViewArr removeAllObjects];
_imageArr = nil;
_imageArr = [NSArray arrayWithArray:images];
[self initLayout];
}
//重新載入圖檔(image name對象)
- (void)reloadImageNames:(NSArray*)imageNames{
NSMutableArray * images = [NSMutableArray array];
for (NSString * imagePath in imageNames) {
[images addObject:[UIImage imageNamed:imagePath]];
}
[self reloadImage:images];
}
#pragma mark - initUI
- (void)initLayout{
NSInteger imageCount = _imageArr.count;
if(imageCount < ){
[self loadAlertText];
return;
}
for (int i = ; i < ; i++) {
UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake((i - ) * CGRectGetWidth(_frame), , CGRectGetWidth(_frame), CGRectGetHeight(_frame))];
imageView.tag = i;
if(i == ){
imageView.image = _imageArr[];
}else if(i == ){
imageView.image = _imageArr[imageCount - ];
}else{
NSInteger index = i >= imageCount ? imageCount - : i - ;
imageView.image = _imageArr[index];
}
[self addSubview:imageView];
[_imageViewArr addObject:imageView];
}
_pageCtl = [[UIPageControl alloc]initWithFrame:CGRectMake(, CGRectGetHeight(_frame) - KWHC_PAGE_CONTROL_HEIGHT, CGRectGetWidth(_frame), KWHC_PAGE_CONTROL_HEIGHT)];
_pageCtl.backgroundColor = [UIColor clearColor];
_pageCtl.numberOfPages = imageCount;
[self addSubview:_pageCtl];
UIButton * clearBtn = [UIButton buttonWithType:UIButtonTypeCustom];
clearBtn.frame = CGRectMake(, , CGRectGetWidth(_frame), CGRectGetHeight(_frame));
clearBtn.backgroundColor = [UIColor clearColor];
[clearBtn addTarget:self action:@selector(clickClearBtn:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:clearBtn];
if(imageCount > ){
self.isCanTouchScroll = YES;
self.isCanAutoScroll = YES;
}
}
#pragma mark - handleAnimation
//手勢觸摸移動圖檔
- (void)touchMoveImage:(NSInteger)index withDistance:(CGFloat)moveXDistace{
for (NSInteger i = index; i < index + ; i++) {
//移動圖檔
CGPoint currImageViewCenter = ((UIImageView *)_imageViewArr[i]).center;
((UIImageView *)_imageViewArr[i]).center = CGPointMake(currImageViewCenter.x + moveXDistace, currImageViewCenter.y);
}
}
//動畫切換圖檔
- (void)animationMoveImage:(NSInteger)index withOri:(WHC_TOUCH_ORI)touchOri{
self.isCanTouchScroll = NO;
[UIView animateWithDuration:KWHC_MOVE_IMAGE_DURING animations:^{
//移動圖檔
for (NSInteger i = index; i < index + ; i++) {
UIImageView * imageView = (UIImageView *)_imageViewArr[i];
CGFloat distanceX = CGRectGetWidth(_frame) / ;
if(touchOri == LEFT){
distanceX = -distanceX;
imageView.center = CGPointMake((i - ) * CGRectGetWidth(_frame) + distanceX , imageView.center.y);
}else{
imageView.center = CGPointMake(i * CGRectGetWidth(_frame) + distanceX , imageView.center.y);
}
}
} completion:^(BOOL finished) {
//動态交換圖檔控件數組位子
if(touchOri == LEFT){
_currentIndex++;
if(_currentIndex >= _imageArr.count){
_currentIndex = ;
}
[_imageViewArr exchangeObjectAtIndex: withObjectAtIndex:];
[_imageViewArr exchangeObjectAtIndex: withObjectAtIndex:];
}else{
_currentIndex--;
if(_currentIndex < ){
_currentIndex = _imageArr.count - ;
}
[_imageViewArr exchangeObjectAtIndex: withObjectAtIndex:];
[_imageViewArr exchangeObjectAtIndex: withObjectAtIndex:];
}
//設定頁控件目前頁
_pageCtl.currentPage = _currentIndex;
for(int i = ; i < _imageViewArr.count; i++){
//重新整理切換後新或者舊圖檔顯示
UIImageView * imageView = _imageViewArr[i];
imageView.center = CGPointMake( i * CGRectGetWidth(_frame) - CGRectGetWidth(_frame) / , imageView.center.y);
if(i == ){
NSInteger index = _currentIndex - ;
if(index < ){
index = _imageArr.count - ;
}
imageView.image = _imageArr[index];
}else if(i == ){
imageView.image = _imageArr[_currentIndex];
}else{
NSInteger index = _currentIndex + ;
if(index >= _imageArr.count){
index = ;
}
imageView.image = _imageArr[index];
}
}
self.isCanTouchScroll = YES;
}];
}
//動畫恢複切換狀态(手勢移動距離不滿足條件需要恢複初始狀态)
- (void)animationResetImage:(NSInteger)index withOri:(WHC_TOUCH_ORI)touchOri{
if(touchOri == LEFT){
index = ; //向左恢複初始下标
}else{
index = ; //向右恢複初始下标
}
[UIView animateWithDuration:KWHC_MOVE_IMAGE_DURING animations:^{
for (NSInteger i = index; i < + index; i++) {
UIImageView * imageView = (UIImageView *)_imageViewArr[i];
CGFloat distanceX = CGRectGetWidth(_frame) / ;
if(touchOri == LEFT){
imageView.center = CGPointMake(distanceX + (i - ) * distanceX * , imageView.center.y);
}else{
imageView.center = CGPointMake(-distanceX + i * distanceX * , imageView.center.y);
}
}
}];
}
#pragma mark - handleGesture
//觸摸手勢處理
- (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture{
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:
if(self.isCanAutoScroll){
_isStartTouch = YES;
self.isCanAutoScroll = NO;
}
_startPoint = [panGesture locationInView:self];
break;
case UIGestureRecognizerStateChanged:{
CGPoint currentPoint = [panGesture locationInView:self];
CGFloat moveXInstance = currentPoint.x - _startPoint.x;
if([panGesture velocityInView:self].x < ){
//left
if (_currentMoveOri == RIGHT) {
[self touchMoveImage:KWHC_RIGHT_START_INDEX withDistance:-fabsf(moveXInstance)];
}else{
_currentMoveOri = LEFT;
[self touchMoveImage:KWHC_LEFT_START_INDEX withDistance:-fabsf(moveXInstance)];
}
}else{
//right
if(_currentMoveOri == LEFT){
[self touchMoveImage:KWHC_LEFT_START_INDEX withDistance:fabsf(moveXInstance)];
}else{
_currentMoveOri = RIGHT;
[self touchMoveImage:KWHC_RIGHT_START_INDEX withDistance:fabsf(moveXInstance)];
}
}
_startPoint = currentPoint;
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:{
UIImageView * imageView = _imageViewArr[];
if(imageView.center.x <= ){
[self animationMoveImage:KWHC_LEFT_START_INDEX withOri:LEFT];
}else if(imageView.center.x >= CGRectGetWidth(_frame)){
[self animationMoveImage:KWHC_RIGHT_START_INDEX withOri:RIGHT];
}else{
[self animationResetImage:KWHC_RIGHT_START_INDEX withOri:_currentMoveOri];
}
_currentMoveOri = NONE;
if(_isStartTouch){
self.isCanAutoScroll = YES;
}
_isStartTouch = NO;
}
break;
default:
break;
}
}
#pragma mark - clickAction
//單擊圖檔調用
- (void)clickClearBtn:(UIButton*)sender{
if(_currentIndex <= _imageArr.count - ){
if(_delegate && [_delegate respondsToSelector:@selector(WHC_AdvertisingWall:clickImage:index:)]){
[_delegate WHC_AdvertisingWall:self clickImage:_imageArr[_currentIndex] index:_currentIndex];
}
}
}
@end
運作效果圖:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISN1QDNzUTMwEDMyQDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
WHC_AdvertisingWallDemo下載下傳