說到輪播圖训裆,估計都不陌生钩骇,各種各樣的輪播圖在各個App上都不斷的被使用,因為輪播圖的界面簡潔并且內容涵蓋豐富郑象,所以經(jīng)常拿來進行使用贡这。但是無論輪播圖的樣式怎么變換,它的實現(xiàn)機制實際上都大同小異厂榛,今天就一點點說一下輪播圖的實現(xiàn)吧盖矫!
實現(xiàn)方案
實現(xiàn)這樣的界面實際上大家都有自己的想法,看到這樣的界面击奶,無疑會想到它的控件分布如下:
- 滾動視圖
- 每個滾動視圖的單元格圖片展示
- 滾動位置導航器(多種風格)
對應的結構圖如下所示:
這不禁讓人想起了兩個控件來實現(xiàn)這樣的效果辈双,一個是UIScrollView,另外一個則是UICollectionView柜砾。這兩個都能實現(xiàn)滾動的效果湃望,因為UICollectionView繼承自UIScrollView,所以就以UIScrollView的實現(xiàn)方式來說起吧痰驱!
首先封裝這個控件之前证芭,我們需要兩個創(chuàng)建滾動視圖的變量,一個是數(shù)量bannerNum担映,以及另外一個變量輪播圖的圖片地址imageLink废士。這兩個變量在使用的時候需要傳遞給我們,然后才能依據(jù)這兩個變量創(chuàng)建相應的滾動視圖蝇完。結合這樣的邏輯官硝,我們可以將其設置為一個代理诅挑,然后使用的時候,通過代理將我們需要的變量傳遞進來也就滿足了創(chuàng)建需求泛源。
代理創(chuàng)建如下:
@protocol LCBannerScrollerViewDelegate <NSObject,UITableViewDelegate>
- (NSInteger )bannerView:(LCBannerScrollerView *)bannerScrollView;
- (NSString *)bannerLinks:(LCBannerScrollerView *)bannerScrollView linkForIndexOfBanner:(NSInteger)indexPath;
@optional
//相應廣告圖的點擊事件
- (void)bannerView:(LCBannerScrollerView *)bannerScrollView didClicked:(NSInteger)index;
@end
然后創(chuàng)建一個ScrollView滾動視圖拔妥,代碼如下:
- (void)creatView{
//初始化數(shù)據(jù)
self.index = 0;
//從代理中獲取對應的滾動圖數(shù)量
NSInteger bannerNum = [self.delegate bannerView:self];
UIScrollView *banerScrollerView = [[UIScrollView alloc]init];
banerScrollerView.frame = CGRectMake(0, 0,self.frame.size.width, self.frame.size.height-BarViewHeight);
banerScrollerView.contentSize = CGSizeMake(self.frame.size.width * (bannerNum+2), 0);
[self addSubview:banerScrollerView];
self.bannerScrollView = banerScrollerView;
banerScrollerView.pagingEnabled = YES;
banerScrollerView.bounces = NO;
banerScrollerView.delegate = self;
banerScrollerView.scrollsToTop = NO;
banerScrollerView.showsHorizontalScrollIndicator = NO;
//創(chuàng)建廣告圖
CGFloat img_x = 0;
CGFloat img_y = 0;
CGFloat img_w = SCREEN_WIDTH;
CGFloat img_h = self.frame.size.height - BarViewHeight;
for (int i = 0; i<bannerNum; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(img_x, img_y, img_w, img_h);
[button addTarget:self action:@selector(bannerTouch:) forControlEvents:UIControlEventTouchUpInside];
NSString *imageLink = [self.delegate bannerLinks:self linkForIndexOfBanner:i];
[button sd_setBackgroundImageWithURL:[NSURL URLWithString:imageLink] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed:@"placeholder3"]];
button.contentMode = UIViewContentModeCenter;
button.tag = i;
[banerScrollerView addSubview:button];
[self.bannerViewArray addObject:button];
img_x += img_w;
}
//創(chuàng)建導航pageController(該項目為底部滑塊滾動條)
CGFloat bar_x = 0;
CGFloat bar_y = img_h;
CGFloat bar_w = self.frame.size.width/bannerNum;
CGFloat bar_h = BarViewHeight;
for (int i=0; i<bannerNum; i++) {
UIView *barView = [[UIView alloc]init];
barView.frame = CGRectMake(bar_x, bar_y, bar_w, bar_h);
barView.tag = i;
[self addSubview:barView];
[self.bottomViewArray addObject:barView];
bar_x += bar_w;
}
//添加滑塊游標
UIView *actionView = [[UIView alloc]init];
if (self.bottomViewArray.count) {
UIView *firstBarView = self.bottomViewArray[0];
actionView.frame = firstBarView.frame;
actionView.backgroundColor = _barViewColor ? _barViewColor : barViewColor;
self.actionBarView = actionView;
[self addSubview:_actionBarView];
}
}
/*
** 將滾動圖的點擊事件傳遞給代理,將點擊事件通過代理來進行回調
*/
- (void)bannerTouch:(UIButton*)button{
[self.delegate bannerView:self didClicked:button.tag];
}
寫完以上代碼达箍,實際上輪播圖的模樣已經(jīng)清晰了没龙,但是輪播圖不能自動滾動,只能拿手進行拖動缎玫。實現(xiàn)自動滾動需要一個定時器來進行循環(huán)的操作硬纤,我們創(chuàng)建一個定時器:
// 釋放時取消定時器
- (void)dealloc {
[self.timer invalidate];
}
//懶加載
- (NSTimer *)timer {
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:AnimotionTime target:self selector:@selector(scrollBanner:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
}
return _timer;
}
有時候為了讓自動滾動變得靈活可控,通常啟動定時器的方法將其設定為對外接口赃磨,通過由外界來控制定時器的啟動筝家。自動滾動開始以后,我們貌似忽略了一個重點內容邻辉,就是滾動導航指示器(通常為UIPageController)的指示溪王,這個滾動的指示我們可以通過UIScrollView的代理中回調的偏移量進行計算得出當前頁。具體如下:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat offset_x = scrollView.contentOffset.x;
self.index = offset_x/scrollView.frame.size.width;
//實時改變底部滑塊的位置
CGFloat offsetX_zoom = (offset_x - SCREEN_WIDTH * self.index) / SCREEN_WIDTH;
UIView *currentView = self.bottomViewArray[self.index];
CGRect frame = currentView.frame;
frame.origin.x += offsetX_zoom * (SCREEN_WIDTH/self.bottomViewArray.count);
self.actionBarView.frame = frame;
}
- (void)scrollBanner:(NSTimer *)timer{
CGFloat offset_x = 0;
CGFloat offset_y = 0;
offset_x = _index * self.frame.size.width;
//讓滾動平滑緩慢
offset_x = _index * self.frame.size.width;
[UIView animateWithDuration:ScrollTime delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
[self.bannerScrollView setContentOffset:CGPointMake(offset_x, offset_y) animated:NO];
} completion:nil];
_index ++;
}
滾動完成以后值骇,我們可能會遇到一個問題莹菱,那就是用手滾動滾動圖的時候,會發(fā)現(xiàn)手勢不能停止自動滾動吱瘩,顯然這樣的結果不是我們想要的道伟,為了解決這個問題,我們在手勢觸發(fā)滾動的時候暫停計時器的及時使碾,等手勢移除之后再將定時器恢復就可以解決問題了蜜徽。解決如下:
//手勢開始觸發(fā)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[self endSchedulTime];
}
//手勢結束觸發(fā)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
//恢復定時器計時
[self startSchedulTime];
}
- (void)endSchedulTime{
// 停止計時
[self.timer setFireDate:[NSDate distantFuture]];
}
- (void)startSchedulTime{
// 開始計時(手勢停止后,要延遲一段時間再進行滾動票摇,否則手勢一旦停止就立即滾動會顯得滾動倉促拘鞋,這個時間根據(jù)需求來定)
[self.timer setFireDate:[NSDate dateWithTimeInterval:1.5 sinceDate:[NSDate date]]];
}
好了,簡單的輪播圖就這樣實現(xiàn)了兄朋,是不是很簡單呢掐禁!效果如下:
至于無限輪播圖,就等到下一篇在進行詳細的介紹吧颅和!