IOS無限輪播圖

思路:在ScrollView的contentSiz設置成ScrollView寬的度的三倍。建立三個循環的View。當滑動的時候,正常滑動活動結束。滑動結束設置contentOffset將視圖滑動到中間去。將後面的數據賦值到中間。。。簡單說就是視圖只顯示中間一張視,交換數據實現不一樣數據的顯示。。網絡

#import <UIKit/UIKit.h>

@protocol YQImageLoopDelegate <NSObject>

- (void)YQImageLoopConfigDataArray:(NSArray *)yq_dataArray loopView:(UIView *)yq_loopView index:(NSInteger)index;
@optional
- (void)YQImageLoopClickImageOfindex:(NSInteger)index dataArray:(NSArray *)yq_dataArray;

@end



@interface YQImageLoop : UIView

- (instancetype)initWithFrame:(CGRect)frame loopView:(UIView *)loopView loopDelagate:(id<YQImageLoopDelegate>)delegate;// 初始化
@property (nonatomic, strong) UIScrollView *yq_scrollView;
@property (nonatomic, strong) UIPageControl *yq_pageControl;
@property (nonatomic, assign) NSTimeInterval yq_timerLoopTime;     // timer循環時間
@property (nonatomic, assign) NSTimeInterval yq_animactionTime;    // 動畫時間
@property (nonatomic, strong) NSArray *yq_dataArray;        // 循環的數據
@property (nonatomic, assign) BOOL yq_isLoop;                      // 是否循環
@property (nonatomic, assign) id<YQImageLoopDelegate>delegate;     // 代理

#pragma mark 事件-timer事件
-(void)addTimer:(NSTimeInterval)timeInterval;
- (void)cancelTimerLoop;
@end

 

#import "YQImageLoop.h"

typedef NS_ENUM(NSInteger, YQScrollDirection)
{
    YQRight,
    YQLeft,
};

@interface YQImageLoop ()<UIScrollViewDelegate>
@property (nonatomic, strong) NSTimer *yq_timer;            // 循環timer定時器
@property (nonatomic, strong) UIView *yq_loopView;          // 循環的視圖
@property (nonatomic, strong) NSMutableArray *yq_recordLoopViewArray; // 存儲循環視圖
@property (nonatomic, assign) BOOL isDragg;    // 是否拖拽
@property (nonatomic, assign) BOOL isGetData;  // 是否活的輪播的數據

@property (nonatomic, strong) UITapGestureRecognizer *tapGR;

@end

@implementation YQImageLoop


- (instancetype)initWithFrame:(CGRect)frame loopView:(UIView *)loopView loopDelagate:(id<YQImageLoopDelegate>)delegate
{
    self = [super initWithFrame:frame];
    if (self) {
        _delegate = delegate;
        _yq_loopView = loopView;
        [self addDatas];
        [self addViews];
    }
    return self;
}

#pragma mark 初始
- (void)addViews
{
    self.yq_scrollView.frame = self.frame;
    [self addSubview:self.yq_scrollView];
    [self addSubview:self.yq_pageControl];
    
    self.tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGRAction:)];
    [self addGestureRecognizer:_tapGR];
}
- (void)addDatas
{
    _isGetData = NO;
     _isDragg = NO;
    _yq_dataArray = [[NSMutableArray alloc] initWithCapacity:30];
     [self addObserver:self forKeyPath:@"yq_dataArray" options:NSKeyValueObservingOptionNew context:nil];
}
#pragma mark 初始-事件
#pragma mark 初始-事件-添加循環視圖
- (void)configScrollViewLoopView
{
    for (int i=0; i<3; i++) {
         UIView *newLoopView = [self duplicate:self.yq_loopView];
        newLoopView.frame = CGRectMake(self.frame.size.width*i, 0, self.frame.size.width, self.frame.size.height);
        [self.yq_recordLoopViewArray addObject:newLoopView];
        [_yq_scrollView addSubview:newLoopView];
    }
}
// 複製一份view
- (UIView*)duplicate:(UIView*)view1
{
    NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject:view1];
    return [NSKeyedUnarchiver unarchiveObjectWithData:tempArchive];
}

- (void)setYq_timerLoopTime:(NSTimeInterval)yq_timerLoopTime
{
    _yq_timerLoopTime = yq_timerLoopTime;
    [self addTimer:_yq_timerLoopTime];
}

#pragma mark 代理-delegate
#pragma mark 代理-scrollViewDelegate

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // 拖拽開始
    self.isDragg = YES;
    [self cancelTimerLoop];
    
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    // 拖拽完成
    if (self.isDragg == YES) {
        [self addTimer:self.yq_timerLoopTime];
        self.isDragg = NO;
    }
    // changDataOrPage
    [self YQScrollViewDidEndDecelerating:_yq_scrollView.contentOffset.x isGetData:_isGetData];
}


#pragma mark 事件
#pragma mark 事件-timer事件
-(void)addTimer:(NSTimeInterval)timeInterval
{
    if (self.yq_timer == nil) {
        self.yq_timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(timeLoopAction:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:_yq_timer forMode:NSRunLoopCommonModes];
    }
}
- (void)cancelTimerLoop
{
    [self.yq_timer invalidate];
    self.yq_timer = nil;
}
- (void)timeLoopAction:(NSTimer *)sender
{
    [UIView animateWithDuration:self.yq_animactionTime animations:^{
        self.yq_scrollView.contentOffset = CGPointMake(self.frame.size.width*2, 0);
    } completion:^(BOOL finished) {
        self.yq_scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        if (_isGetData == YES) {
            [self changeDataAndPage:YQLeft];
        }else{
            [self changePage:YQLeft];
        }
    }];
}

#pragma mark 事件-滑動完成改變數據、
- (void)YQScrollViewDidEndDecelerating:(CGFloat)contentOffsetX isGetData:(BOOL)getData
{
        if (contentOffsetX == 0) {
            if (getData == YES){
                [self changeDataAndPage:YQRight];
            }else{
                [self changePage:YQRight];
            }
            _yq_scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        }else if(contentOffsetX == self.frame.size.width*2){
            if (getData == YES) {
                [self changeDataAndPage:YQLeft];
            }else{
                [self changePage:YQLeft];
            }
            _yq_scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        }
}


// data and page
- (void)changeDataAndPage:(YQScrollDirection)scrollDirection
{
    [self changePage:scrollDirection];
    [self changeData];
}
// page
- (void)changePage:(YQScrollDirection)scrollDirection
{
    if (scrollDirection == YQRight) {
        // pageCotrol 變化
        if (_yq_pageControl.currentPage == 0){
            _yq_pageControl.currentPage = _yq_pageControl.numberOfPages-1;
        }else{
            _yq_pageControl.currentPage -= 1;
        }
    }else if(scrollDirection == YQLeft){
        if(_yq_pageControl.currentPage == _yq_pageControl.numberOfPages-1){
            _yq_pageControl.currentPage = 0;
        }else{
            _yq_pageControl.currentPage += 1;
        }
    }
}
// data
- (void)changeData
{
    if (_yq_pageControl.currentPage == 0){
        if (_delegate && [_delegate respondsToSelector:@selector(YQImageLoopConfigDataArray:loopView:index:)]) {
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[0] index:_yq_pageControl.numberOfPages-1];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[1] index:0];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[2] index:1];
        }
    }else if(_yq_pageControl.currentPage == _yq_pageControl.numberOfPages-1){
        if (_delegate && [_delegate respondsToSelector:@selector(YQImageLoopConfigDataArray:loopView:index:)]) {
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[0] index:_yq_pageControl.currentPage-1];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[1] index:_yq_pageControl.currentPage];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[2] index:0];
        }
    }else{
        if (_delegate && [_delegate respondsToSelector:@selector(YQImageLoopConfigDataArray:loopView:index:)]) {
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[0] index:_yq_pageControl.currentPage-1];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[1] index:_yq_pageControl.currentPage];
            [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[2] index:_yq_pageControl.currentPage+1];
        }
    }
}

#pragma mark 監聽
#pragma mark 監聽-屬性
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"yq_dataArray"]) {
        if (change[@"new"] != nil && ([change[@"new"] isKindOfClass:[NSArray class]] && ([(NSArray *)change[@"new"] count] != 0) && ([change[@"new"] isKindOfClass:[NSDictionary class]]|| [(NSDictionary *)change[@"new"] count] != 0))){
            _isGetData = YES;
            [self observeValueFinish];
        }
    }
}
#pragma mark 監聽-事件
- (void)observeValueFinish
{
    self.yq_pageControl.numberOfPages = self.yq_dataArray.count;
    if (_delegate && [_delegate respondsToSelector:@selector(YQImageLoopConfigDataArray:loopView:index:)]) {
        [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[0] index:_yq_dataArray.count-1];
        [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[1] index:0];
        [_delegate YQImageLoopConfigDataArray:_yq_dataArray loopView:_yq_recordLoopViewArray[2] index:1];
    }
}


#pragma mark 點擊事件
- (void)tapGRAction:(UITapGestureRecognizer *)sender
{
    if (_delegate && [_delegate respondsToSelector:@selector(YQImageLoopClickImageOfindex:dataArray:)]) {
        [_delegate YQImageLoopClickImageOfindex:self.yq_pageControl.currentPage dataArray:_yq_dataArray];
    }
}


#pragma mark setter and getter
- (UIPageControl *)yq_pageControl
{
    if (_yq_pageControl == nil) {
        _yq_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.frame.size.height-30, self.frame.size.width, 30)];
        _yq_pageControl.numberOfPages = 4;
    }
    return _yq_pageControl;
}
- (UIScrollView *)yq_scrollView
{
    if (_yq_scrollView == nil){
        _yq_scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
        _yq_scrollView.delegate = self;
        _yq_scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame)*3, CGRectGetHeight(self.frame));
        _yq_scrollView.contentOffset = CGPointMake(CGRectGetWidth(self.frame), 0);
        _yq_scrollView.pagingEnabled = YES;
        _yq_scrollView.bounces = NO;
        _yq_scrollView.showsHorizontalScrollIndicator = NO;
        _yq_scrollView.showsVerticalScrollIndicator = NO;
        [self configScrollViewLoopView];
    }
    return _yq_scrollView;
}

- (NSMutableArray *)yq_recordLoopViewArray
{
    if (_yq_recordLoopViewArray == nil) {
        _yq_recordLoopViewArray = [[NSMutableArray alloc] initWithCapacity:30];
    }
    return _yq_recordLoopViewArray;
}


- (void)dealloc
{
    [self removeObserver:self forKeyPath:@"yq_dataArray" context:nil];
}

 

注意事項:NSTimer 加到當前的runloop中,才能真正的實現循環。。。你們不良瞭解runloop的能夠自行百度去吧。在下就不在這班門弄斧,講一些與主題無關的了。。。app

看一下如何使用吧oop

// 圖片資源
     self.imageAddressArray = [[NSArray alloc] initWithObjects:@"http://img1.3lian.com/2015/w1/47/d/1.jpg",@"http://img1.3lian.com/2015/w1/47/d/9.jpg",@"http://img1.3lian.com/2015/w1/47/d/8.jpg",@"http://img1.3lian.com/2015/w2/10/d/46.jpg",@"http://img1.3lian.com/2015/w1/47/d/7.jpg",@"http://img1.3lian.com/2015/w1/47/d/6.jpg", nil];
    
    // 自定義循環視圖
    UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"zw.png"]];
    //_________________________________________________________
    _yqImageLoop = [[YQImageLoop alloc] initWithFrame:self.view.frame loopView:image loopDelagate:self];
    _yqImageLoop.yq_pageControl.currentPageIndicatorTintColor = [UIColor redColor];
    _yqImageLoop.yq_timerLoopTime = 3.0f;
    _yqImageLoop.yq_animactionTime = 1.5f;
    [self.view addSubview:_yqImageLoop];
    
    
    // 延遲賦數據,模仿網絡請求
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        _yqImageLoop.yq_dataArray = _imageAddressArray;
    });

 

// 輪播圖賦值數據
- (void)YQImageLoopConfigDataArray:(NSArray *)yq_dataArray loopView:(UIView *)yq_loopView index:(NSInteger)index
{
    [((UIImageView *)yq_loopView) sd_setImageWithURL:[NSURL URLWithString:yq_dataArray[index]] placeholderImage:[UIImage imageNamed:@"zw.png"]];
}

// 點擊輪播
- (void)YQImageLoopClickImageOfindex:(NSInteger)index dataArray:(NSArray *)yq_dataArray
{
    NSLog(@"%@",yq_dataArray[index]);
}

/*
  在視圖將要出現的時候加上事件循環, 消失的時候取消事件循環
 */
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [_yqImageLoop addTimer:3.0f]; // 添加時間循環
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [_yqImageLoop cancelTimerLoop]; // 取消事件循環
}

 

有什麼好的建議,有更好的想法。聯繫826001000.謝謝 動畫

相關文章
相關標籤/搜索