scrollView結合pageControl視圖切換

(一)開篇描述函數

(1)本blog中的實例是參考ScrollViewLoop,增長本身對demo中代碼的理解;oop

(2)實例中運用到了runtime的建立屬性的方法objc_setAssociatedObject和獲取建立屬性的方法objc_getAssociatedObject;atom

(3)NSObject cancelPreviousPerformRequestsWithTarget,取消performSelector方法註冊的函數。code


(二)實例以及代碼解析orm

#import <UIKit/UIKit.h>


@protocol bnnerTViewDelegate <NSObject>

- (void) Log;

@end

@interface bnnerTView : UIView <UIScrollViewDelegate>
{
    BOOL _isAutoPlay;
}

@property (nonatomic ,assign) id<bnnerTViewDelegate> delegate;

- (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto;

- (void)scrollToIndex:(int)aIndex;
@end
#import "bnnerTView.h"
#import <objc/runtime.h>

@interface bnnerTView ()
{
    UIScrollView *scroller;
    UIPageControl *pageControl;
}

@end

@implementation bnnerTView

static NSString *SG_FOCUS_ITEM_ASS_KEY = @"loopScrollview";
static CGFloat SWITCH_FOCUS_PICTURE_INTERVAL = 3.0; //每隔三秒切換一次

//自定義的init函數,主要是傳遞必要的參數,此函數能夠繼續完善;如能夠開放設置自動切換的時間間隔的值SWITCH_FOCUS_PICTURE_INTERVAL; - (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto Interval:(NSTimeInterval *)times
- (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto

{
    self = [super initWithFrame:frame];
    
    if (self) {
        
        NSMutableArray *ItemsArray = [NSMutableArray arrayWithArray:Items];
        
        objc_setAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY, ItemsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        _isAutoPlay = isAuto;
        
        [self initViews];
    }
    
    return self;
}


//初始化view,建立scrollView,pageControl,並設置其屬性,scrollView開始執行自動切換的操做
//設置scrollView的Subview和contentSize
//設置pageControl的numberOfPages
- (void)initViews {
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    scroller = [[UIScrollView alloc] initWithFrame:self.bounds];
    scroller.scrollsToTop = NO;
    scroller.pagingEnabled = YES;
    scroller.delegate = self;
    
    
    pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 16 - 10, self.bounds.size.width, 10)];
    pageControl.userInteractionEnabled = NO;
    pageControl.numberOfPages = ItemsArray.count > 1 ? ItemsArray.count - 2 : ItemsArray.count;
    
    
    [self addSubview:scroller];
    [self addSubview:pageControl];
    
    for (int i = 0; i < ItemsArray.count; i ++) {
        
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(i * scroller.frame.size.width, 0, scroller.frame.size.width, scroller.frame.size.height)];
        
        imageView.backgroundColor = i % 2 ? [UIColor redColor] : [UIColor blueColor];
        
        [scroller addSubview:imageView];
    }
    
    scroller.contentSize = CGSizeMake(scroller.frame.size.width * ItemsArray.count, scroller.frame.size.height);
    
    if (ItemsArray.count > 1)
    {
        [scroller setContentOffset:CGPointMake(scroller.frame.size.width, 0) animated:NO];
        if (_isAutoPlay)
        {
            [self performSelector:@selector(changeCurrentItems) withObject:nil afterDelay:SWITCH_FOCUS_PICTURE_INTERVAL];
        }
    }
}


//定義scrollView自動切換的函數
//解釋cancelPreviousPerformRequestsWithTarget:取消performSelector方法註冊的函數
//changeCurrentItems使用的方法就是,先取消註冊performSelector方法,最後又註冊performSelector方法。
//scroller.frame.size.width表示每切換一次所增長的contentOffset.x的距離
- (void)changeCurrentItems {
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(changeCurrentItems) object:nil];
    
    int targetX = scroller.contentOffset.x + scroller.frame.size.width;
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    targetX = (targetX / scroller.frame.size.width) * scroller.frame.size.width;
    
    [self moveToTargetPosition:targetX];
    
    if (ItemsArray.count > 1 && _isAutoPlay) {
        
        [self performSelector:@selector(changeCurrentItems) withObject:nil afterDelay:SWITCH_FOCUS_PICTURE_INTERVAL];
    }
}


//在滑動scroller的時候會觸發此委託函數,所以在此委託函數中進行頁碼的計算以及scroller的contentOffset的計算
//contentOffset計算的方法:獲取滑動scroller的contentOffset.x,並進行比較(scroller.frame.size.width * (ItemsArray.count - 1)滑動到了最後一頁,就將scroller的contentOffset設置成首頁的位置;反之,將contentOffset設置成最後一頁的位置,即contentOffset.x <= 0)
//page計算的方法:(scrollView.contentOffset.x + scroller.frame.size.width / 2.0) / scroller.frame.size.width;其中scroller.frame.size.width表示每滑動一次的距離。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    float targetX = scrollView.contentOffset.x;
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    if (ItemsArray.count >= 3) {
        
        //當前顯示的是最後一張圖片
        if (targetX >= scroller.frame.size.width * (ItemsArray.count - 1)) {
            
            targetX = scroller.frame.size.width;
            [scroller setContentOffset:CGPointMake(targetX, 0) animated:NO];
        }
        
        //當前顯示的是第一張圖片
        else if (targetX <= 0) {
            
            targetX = scroller.frame.size.width * (ItemsArray.count - 2);
            [scroller setContentOffset:CGPointMake(targetX, 0) animated:NO];
        }
    }
    
    
    int page = (scrollView.contentOffset.x + scroller.frame.size.width / 2.0) / scroller.frame.size.width;
    
    if (ItemsArray.count > 1)
    {
        page --;
        if (page >= pageControl.numberOfPages) { //向左滑動,頁碼從最後一頁跳轉至第一頁
            
            page = 0;
        }
        else if(page < 0) { //向右滑動,頁碼從第一頁跳轉至最後一頁
            
            page = (int)pageControl.numberOfPages - 1;
        }
    }
    
    pageControl.currentPage = page;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    
    if (!decelerate) {
        
        int targetX = scrollView.contentOffset.x + scroller.frame.size.width;
        
        targetX = (int)(targetX + scroller.frame.size.width) / scroller.frame.size.width;
        
        [self moveToTargetPosition:targetX];
    }
}


//設置scroller的contentOffset爲targetX
- (void)moveToTargetPosition:(CGFloat)targetX {
    
    [scroller setContentOffset:CGPointMake(targetX, 0) animated:YES];
}


//能夠設置scroller的起始頁碼
- (void)scrollToIndex:(int)aIndex {
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    if ([ItemsArray count] > 1) {
        
        if (aIndex >= (ItemsArray.count - 2)) {
            
            aIndex = (int)ItemsArray.count - 3;
        }
        
        [self moveToTargetPosition:scroller.frame.size.width * (aIndex + 1)];
    }
    else {
        
        [self moveToTargetPosition:0];
    }
    
    [self scrollViewDidScroll:scroller];
}
@end

代碼的理解都寫在了函數的開頭處;本實例還有不少可完善的(完善delegate增長可操做性等)。
blog

相關文章
相關標籤/搜索