天天看點

iOS開發系列之常用自定義控件開發集—自動廣告牆圖檔控件開發

現在很多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
           

運作效果圖:

iOS開發系列之常用自定義控件開發集—自動廣告牆圖檔控件開發

WHC_AdvertisingWallDemo下載下傳