(一)開篇描述函數
(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