前言 市面上絕大部分的APP被打開之後映入眼帘的都是一個美輪美奐的輪播器,所以能做出一個符合需求、高效的輪播器成為了一個程式員的必備技能。所以今天的這篇博客就來談談輪播器這個看似簡單的控制項其中蘊含的道理。正文 首先我們來分析一下該如何去實現一個類似下圖的輪播器(圖片數量、URL由伺服器返...
前言
市面上絕大部分的APP被打開之後映入眼帘的都是一個美輪美奐的輪播器,所以能做出一個符合需求、高效的輪播器成為了一個程式員的必備技能。所以今天的這篇博客就來談談輪播器這個看似簡單的控制項其中蘊含的道理。
正文
首先我們來分析一下該如何去實現一個類似下圖的輪播器(圖片數量、URL由伺服器返回):
策略一:UIScrollView->UIImageView->NSTimer輪詢 這算是常規的策略,但是如果仔細想想,如果伺服器返回給你50圖片是不是就需要創建50個UIImageView來做容器。這種性能肯定不是最優的。其次所有的UIImageView是按照次序排列,腦補一下如果到最後一張圖片要重新回到第一張圖片你的話,UIScrollView會被升拉到第一個位置。效果太差!
策略二:想想UITableViewCell的重覆利用,我們也可以重覆利用其中的UIImageView。對於我們來說輪播器三個UIImageView就足夠用了,分為當前視野中的CenterImageView、前一張LeftImageView、後一張RightImageView。不同的是他們之間的圖片切換,下麵我們就嘗試去做高效的輪播器。
代碼實現
- 初始化所需控制項:
2.寫一個專門控制沒次滑動結束去計算左中右三張序號並載入成對應的圖片。
/** 這裡我起名叫reloadAllImageView */
-(void)reloadAllImageView{
CGPoint offset = _backScrollView.contentOffset; /** 獲取到scroll的X軸偏移量 */
if (offset.x == 2 * DeviceWidth){ /** 這裡有兩種邊界情況要處理 (1).由first—>last (2)last->first */
/** (2) */
_centerImageIndex = (_centerImageIndex + 1)%3; /** 3代表圖片的數量,這裡要主頁類型的強轉換。_centerImageIndex(NSUInteger)用於記錄當前圖片序號*/
_pageControl.currentPage = (_pageControl.currentPage + 1)%3;
}
else if (offset.x == 0){
/** (1) */
if (_centerImageIndex == 0) { /** 一種特殊情況 當_centerImageIndex等於0的時候 去計算(_centerImageIndex - 1) % 3並不是我們想要的結果 */
_centerImageIndex = 3; /** 嘗試了很久,計算類型轉換也就只有三張圖片會有問題。如果有興趣的朋友可以進行深入研究 */
} /** -1 % 3 = 0 如果都是有符號的結果是-1,如果按照無符號處理的話結果是0。難道計算過程應該先向前借位再進行計算? */
_centerImageIndex = (_centerImageIndex - 1) % 3;
_pageControl.currentPage = (_pageControl.currentPage - 1)%3;
}
_centerImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"圖%d.jpg",_centerImageIndex + 1]];
NSUInteger leftImageViewIndex = (_centerImageIndex - 1)%3;
NSUInteger rightImageViewIndex = (_centerImageIndex + 1)%3;
if (leftImageViewIndex == 0 && _centerImageIndex == 0) { /** 同上暫時處理計算特殊情況 */
leftImageViewIndex = 2;
}
_leftImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"圖%d.jpg",leftImageViewIndex + 1]];
_rightImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"圖%d.jpg",rightImageViewIndex + 1]];
}
3.現在輪播器應該可以在邊界正常切換了。現在需要再加上一個計時器來自動滑動即可:
/** 聲明一個定時器 */ /** 用weak的原因:self如果強擁有了Timer,之後你要設置計時器的Traget和選擇子selector的時候,Timer又會保留目標對象直到失效。產生保留環 */
@property(nonatomic,weak)NSTimer * timer;
/** 定時器初始化 */
-(void)initTimer
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:animationTime target:self selector:@selector(updateImageView:) userInfo:nil repeats:YES];
}
-(void)updateImageView:(NSTimer *)timer
{
[_backScrollView setContentOffset:CGPointMake(DeviceWidth*2, 0) animated:YES];
[NSTimer scheduledTimerWithTimeInterval:0.4f target:self selector:@selector(scrollViewDidEndDecelerating:) userInfo:nil repeats:NO];
}
/** 計算載入所有圖片然後移動的中間視野 */
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//重新載入圖片
[self reloadAllImageView];
//移動到當前視野
[_backScrollView setContentOffset:CGPointMake(DeviceWidth, 0)];
//設置腳標
_pageControl.currentPage = _centerImageIndex;
}
4.自此輪播器大概雛形已經搞定了。剩下的就是需要搞定計時器和用戶滑動操作的互斥事件處理。
/**記錄一個bool值用於確定滑動操作的願意你。YES,計時器觸發,NO則為用戶觸發*/
(1).計時器的觸發事件中,肯定是由計時器觸發的滑動。所以這裡bool值為YES
(2).載入替換圖片的時候我們要進行判斷(如果是用戶觸發的時候我們要將計時器取消並從空為0)
if (!bool) {
[self.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:animationTime]];
}
bool = NO;
結尾
由此輪播器就實現了,但是其中還是有問題需要解決<1>.限制必須要三張圖片不然會crash <2>沒有封裝成單獨的scrllview以供使用。後續可能會對這些問題加以思考並重新優化。也許嘗試用UICollection來做也是個很好的想法。
最後經過寫這篇博客也有一個目的,其實任何一個看似簡單的功能要深入挖掘的話還是有很說知識的,也發現了自身的不足。最後如果各位大神們看到了博客有任何想法意見的歡迎下麵留言。大家一起探討一起進步。謝謝各位!