
實(shí)現(xiàn)循環(huán)輪播圖的各種方案
輪播圖的實(shí)現(xiàn)方案有很多種,大體上分為CollectionView和ScrollView實(shí)現(xiàn)的兩個(gè)方向。其中CollectionView實(shí)現(xiàn)的方案較多利用了CollectionView的特性,實(shí)現(xiàn)比較簡單,但是比較受限于CollectionView的這個(gè)框架,而且出于學(xué)習(xí)的目的出發(fā)會(huì)比較不夠深入。ScrollView實(shí)現(xiàn)的比較大眾比較令人滿意的方案是使用三個(gè)UIImageView實(shí)現(xiàn)輪播效果。原理這里有位同學(xué)有提到,iOS無限輪播圖片的兩種方式,就不贅述啦。然后其實(shí)使用兩個(gè)UIImageView也是可以實(shí)現(xiàn)的。但是不管是使用兩個(gè)還是三個(gè)UIImageView,都是只限于可見范圍內(nèi)只存在一個(gè)banner的情況,如果可見范圍內(nèi)有n個(gè)banner,就需要n+2個(gè)UIImageView。所以這種方法還是不夠靈活,看看有沒有其他方案。
本文描述的方案是通過UIScrollView實(shí)現(xiàn)Cell的重用機(jī)制,然后實(shí)現(xiàn)循環(huán)輪播的功能。這樣既可以解決使用2或者3個(gè)UIImageView的不靈活的問題,也可以突破UICollectionView框架的限制,提高組件的可擴(kuò)展性。
如何實(shí)現(xiàn)
用ScrollView實(shí)現(xiàn)類似CollectionView的Cell重用機(jī)制
- 首先為什么要用ScrollView去實(shí)現(xiàn)Cell的重用機(jī)制呢。除了出于學(xué)習(xí)的角度考慮之外,我們知道Cell的重用機(jī)制其實(shí)就是建立一個(gè)Cell的復(fù)用池,當(dāng)可見的Cell滑動(dòng)出屏幕外的時(shí)候?qū)⑵浠厥?,下一個(gè)Cell將要顯示于屏幕上時(shí)從復(fù)用池中拿一個(gè)Cell進(jìn)行復(fù)用,如果沒有就new一個(gè)。所以,假如靜止時(shí)可見范圍內(nèi)只存在一個(gè)banner頁的話,那么最多滑動(dòng)時(shí)可見的就是兩個(gè),一共只需要new兩個(gè)Cell出來。
- 我們先用一個(gè)繼承于UIView的View來承載這個(gè)banner組件,叫KiraBanner。它的結(jié)構(gòu)很簡單,一個(gè)UIScrollView用于滑動(dòng),一個(gè)Cell的集合作為Cell的重用池,一個(gè)PageControl。然后我們在init方法中進(jìn)行初始化。當(dāng)然,在init方法中需要對一些KiraBanner的一些默認(rèn)屬性進(jìn)行初始化設(shè)置,如isCircle(是否循環(huán))、topBottomSpace(上下邊距)、leftRightSpace(左右邊距)等等。
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) NSMutableSet *reuseCells;
@property (nonatomic,retain) UIPageControl *pageControl;
- (instancetype)init {
self = [super init];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit {
self.clipsToBounds = YES;
self.pageCount = 0;
self.isAutoScroll = YES;
//默認(rèn)左右間距為20,上下間距為30
self.leftRightSpace = 20;
self.topBottomSpace = 30;
_currentIndex = 0;
//默認(rèn)自動(dòng)滾動(dòng)時(shí)間間隔為5s
_autoTime = 5.0;
_visibleRange = NSMakeRange(0, 0);
self.reuseCells = [[NSMutableSet alloc] init];
self.scrollView.scrollsToTop = NO;
self.scrollView.clipsToBounds = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.backgroundColor = [UIColor redColor];
_currentIndex = 0;
[self.scrollView setFrame:self.bounds];
[self addSubview:self.scrollView];
}
2.仿照CollectionView的使用,我們需要兩個(gè)委托方法來告訴KiraBanner中banner的數(shù)量以及每個(gè)banner展示的內(nèi)容是什么,也就是KiraBanner的DataSource。
@protocol KiraBannerDataSource <NSObject>
@required
/**
* 設(shè)置banner的數(shù)量
*/
- (NSInteger)numberOfItemsInKiraBanner:(KiraBanner *)banner;
/**
* 設(shè)置某一頁banner的內(nèi)容
*/
- (UIView *)kiraBanner: (KiraBanner *)banner viewForItemAtIndex:(NSInteger)index;
@optional
@end
3.然后我們在KiraBanner中增加一個(gè)Class的屬性,對外提供regiseterClassForCells的方法來注冊Cell。
/**
* 注冊的cell類型
*/
@property (nonatomic, strong) Class cellClass;
- (void)regiseterClassForCells: (Class) cellClass {
self.cellClass = cellClass;
}
4.dequeueReusableCell 方法拿到可復(fù)用Cell,也就是即將進(jìn)入屏幕中的cell的來源
- (UIView *)dequeueReusableCell {
UIView *cell = [self.reuseCells anyObject];
if (cell) {
[self.reuseCells removeObject:cell];
NSLog(@"add a cell");
}
if (!cell) {
cell = [[self.cellClass alloc] init];
NSLog(@"produce a new cell");
}
return cell;
}
- recycleCell方法,用于滑動(dòng)時(shí)將消失于屏幕外的cell回收。
- (void)recycleCell: (UIView *)cell {
[self.reuseCells addObject:cell];
[cell removeFromSuperview];
}
6、我們將每頁banner的size作為一個(gè)委托方法交給外部設(shè)置,同時(shí)增加私有屬性pageSize。包括banner的點(diǎn)擊等方法,都需要作為代理給外部調(diào)用。
@protocol KiraBannerDelegate <UIScrollViewDelegate>
/**
* 設(shè)置一個(gè)page的size
*/
- (CGSize)sizeForPageInKiraBanner:(KiraBanner *)banner;
/**
* 當(dāng)前banner滾動(dòng)到了哪一頁
*/
- (void)didScrollToIndex:(NSInteger)index inKiraBanner:(KiraBanner *)banner;
/**
* 點(diǎn)擊某個(gè)cell
*/
- (void)didSelectCell:(UIView *)cell inKiraBannerAtIndex:(NSInteger)index;
/**
* 當(dāng)前page滾動(dòng)過了整頁的百分比
*/
- (void)didScrollPercent:(float)percent OfPageInScrollView:(UIScrollView *)scrollView;
@end
7、在外部ViewController中簡單配置使用一下KiraBanner,并實(shí)現(xiàn)KiraBannerDataSource和Delegate的委托方法。
- (void)viewDidLoad {
[super viewDidLoad];
self.dataArray = @[@"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg"];
self.banner = [[KiraBanner alloc] initWithFrame:CGRectMake(0, 72, Width, Width * 9 / 16)];
[self.view addSubview:self.banner];
self.banner.backgroundColor = [UIColor blackColor];
self.banner.isCircle = YES;
self.banner.leftRightSpace = 50;
self.banner.topBottomSpace = 30;
self.banner.clipsToBounds = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
[self.banner regiseterClassForCells:[UIImageView class]];
self.banner.bannerType = KiraBannerTypeHorizontal;
self.banner.minimumPageAlpha = 1;
self.banner.dataSource = self;
self.banner.delegate = self;
}
- (UIView *)kiraBanner:(KiraBanner *)banner viewForItemAtIndex:(NSInteger)index {
UIImageView *cell = (UIImageView *)[self.banner dequeueReusableCell];
cell.image = [UIImage imageNamed:self.dataArray[index]];
[cell setContentMode:UIViewContentModeScaleAspectFill];
return cell;
}
- (CGSize)sizeForPageInKiraBanner:(KiraBanner *)banner {
return CGSizeMake(Width - 60, (Width - 60) * 9 / 16);
}
- (NSInteger)numberOfItemsInKiraBanner:(KiraBanner *)banner {
return self.dataArray.count;
}
- (void)didSelectCell:(UIView *)cell inKiraBannerAtIndex:(NSInteger)index {
NSLog(@"banner of index : %ld is clicked.",(long)index);
}
- 前置項(xiàng)已經(jīng)準(zhǔn)備好了,接下來就是在didScrollView的代理方法中去做cell復(fù)用的邏輯。這里封裝一個(gè)方法setVisibleCellsAtContentOffset在didScrollView中調(diào)用,顧名思義就是根據(jù)contentoffset添加可見cell。那怎么做復(fù)用的邏輯呢。首先我們遍歷scrollView中的每個(gè)子Cell,根據(jù)cell的frame.origin.x(拿橫向滑動(dòng)舉例)和frame.size.width計(jì)算并與contentoffset作比較,判斷該cell是否在顯示區(qū)域外,如果是,則調(diào)用recycleCell方法對cell進(jìn)行回收。如果不是,則調(diào)用fillPageAtIndex將cell添加到scrollView上。
- (void)setVisibleCellsAtContentOffset:(CGPoint)offset {
CGPoint startPoint = CGPointMake(offset.x - _scrollView.frame.origin.x, offset.y - _scrollView.frame.origin.y);
CGPoint endPoint = CGPointMake(startPoint.x + self.bounds.size.width, startPoint.y + self.bounds.size.height);
switch (self.bannerType) {
case KiraBannerTypeHorizontal: {
for (UIView *cellView in [self cellSubView]) {
if (cellView.frame.origin.x + cellView.frame.size.width < startPoint.x) {
[self recycleCell:cellView];
}
if (cellView.frame.origin.x > endPoint.x) {
[self recycleCell:cellView];
}
}
NSInteger startIndex = MAX(0, floor(startPoint.x / _pageSize.width));
NSInteger endIndex = MIN(_pageCount, ceil(endPoint.x / _pageSize.width));
_visibleRange = NSMakeRange(startIndex, endIndex - startIndex + 1);
for (NSInteger i = startIndex; i < endIndex ; i++) {
[self fillPageAtIndex:i];
}
}
break;
case KiraBannerTypeVertical: {
for (UIView *cellView in [self cellSubView]) {
if (cellView.frame.origin.y + cellView.frame.size.height < startPoint.y) {
[self recycleCell:cellView];
}
if (cellView.frame.origin.y > endPoint.y) {
[self recycleCell:cellView];
}
}
NSInteger startIndex = MAX(0, floor(startPoint.y / _pageSize.height));
NSInteger endIndex = MIN(_pageCount, ceil(endPoint.y / _pageSize.height));
//visibleRange表示可見的banner的index范圍
_visibleRange = NSMakeRange(startIndex, endIndex - startIndex + 1);
for (NSInteger i = startIndex; i < endIndex ; i++) {
[self fillPageAtIndex:i];
}
}
break;
default:
break;
}
}
- (NSArray *) cellSubView {
NSMutableArray * cells = [[NSMutableArray alloc] init];
for (UIView *subView in self.scrollView.subviews) {
if ([subView isKindOfClass:[_cellClass class]]) {
[cells addObject:subView];
}
}
return [cells copy];
}
- (void)fillPageAtIndex:(NSInteger)index {
//cellForIndex的實(shí)現(xiàn)在后面給出,現(xiàn)在只需要知道這是根據(jù)index取到對應(yīng)的cell的方法
UIView *cell = [self cellForIndex:index];
if (!cell) {
UIView *cell = [self.dataSource kiraBanner:self viewForItemAtIndex:index % self.numberOfItems];
cell.clipsToBounds = YES;
switch (self.bannerType) {
case KiraBannerTypeHorizontal: {
float originX = index * self.pageSize.width;
cell.frame = CGRectMake(originX,
self.topBottomSpace,
self.pageSize.width,
self.pageSize.height);
}
break;
case KiraBannerTypeVertical: {
float originY = index * self.pageSize.height;
cell.frame = CGRectMake(self.leftRightSpace,
originY,
self.pageSize.width,
self.pageSize.height);
}
break;
default:
break;
}
}
}
- cellForIndex 在上述的fillPageAtIndex方法中,我們看到需要將index對應(yīng)的cell拿出來重用。但是我們的重用池是Set不是Array,無法用下標(biāo)直接訪問,所以需要將index和cell以某種關(guān)系聯(lián)系起來。這邊我們采用的是runtime的關(guān)聯(lián)對象方法,將index轉(zhuǎn)換為NSNumber并將其與cell對象關(guān)聯(lián)在一起。關(guān)聯(lián)的代碼寫在fillPageAtIndex中,然后在cellForIndex方法中讀取,最后在recycleCell的時(shí)候需要進(jìn)行remove操作。
//在fillPageAtIndex中補(bǔ)充
if (cell) {
//將cellforindex方法的地址作為objc_setAssociatedObject的key,保證唯一性
objc_setAssociatedObject(cell, @selector(cellForIndex:),[NSNumber numberWithInteger:index], OBJC_ASSOCIATION_COPY);
[self.scrollView insertSubview:cell atIndex:0];
}
- (UIView *) cellForIndex: (NSInteger)index {
for (UIView *cellView in [self cellSubView]) {
NSNumber *value = objc_getAssociatedObject(cellView, @selector(cellForIndex:));
if (value.integerValue == index) {
return cellView;
}
}
return nil;
}
- (void)recycleCell: (UIView *)cell {
objc_removeAssociatedObjects(cell);
[self.reuseCells addObject:cell];
[cell removeFromSuperview];
}
10.最后在scrollViewDidScroll中調(diào)用setVisibleCellsAtContentOffset方法,理論上到這里是已經(jīng)完成cell的復(fù)用邏輯了。
實(shí)現(xiàn)KiraBanner的循環(huán)輪播
1.在上述過程中已經(jīng)實(shí)現(xiàn)了Cell的復(fù)用邏輯,其實(shí)就是非循環(huán)banner的實(shí)現(xiàn)。但是現(xiàn)在的頁面沒有單頁滑動(dòng)的效果,所以我們需要對ScrollView進(jìn)行設(shè)置。
self.scrollView.pagingEnabled = YES;
2.reloadData方法 我們需要在reloadData方法中判斷是否循環(huán),如果是,則將scrollView的contentSize設(shè)置為3組banner的大小,并且設(shè)置scrollView的初始contentOffset為第二組banner第一個(gè)的位置。
{
_needsReload = YES;
//reload的時(shí)候移除所有cell
for (UIView *view in self.scrollView.subviews) {
if ([NSStringFromClass(view.class) isEqualToString:NSStringFromClass(_cellClass.class)]) {
[view removeFromSuperview];
}
}
//停止計(jì)時(shí)器
[self stopTimer];
if (_needsReload) {
if (self.dataSource && [self.dataSource respondsToSelector:@selector(numberOfItemsInKiraBanner:)]) {
_numberOfItems = [self.dataSource numberOfItemsInKiraBanner:self];
if (self.isCircle) {
//如果是循環(huán)banner,則把scrollView的長度設(shè)為3組
_pageCount = self.numberOfItems == 1 ? 1 : self.numberOfItems * 3;
} else {
_pageCount = self.numberOfItems == 1 ? 1 : self.numberOfItems;
}
if (_pageCount == 0) {
return;
}
if (self.pageControl && [self.pageControl respondsToSelector:@selector(setNumberOfPages:)]) {
[self.pageControl setNumberOfPages:self.numberOfItems];
}
}
//重置page的寬度
CGFloat width = _scrollView.bounds.size.width - 4 * self.leftRightSpace;
_pageSize = CGSizeMake(width, width * 9 / 16);
if (self.delegate && [self.delegate respondsToSelector:@selector(sizeForPageInKiraBanner:)]) {
_pageSize = [self.delegate sizeForPageInKiraBanner:self];
}
[_reuseCells removeAllObjects];
_visibleRange = NSMakeRange(0, 0);
switch (self.bannerType) {
case KiraBannerTypeHorizontal: {
[self.scrollView setFrame:CGRectMake(0, 0, _pageSize.width, _pageSize.height)];
[self.scrollView setContentSize:CGSizeMake(_pageSize.width * _pageCount, 0)];
_scrollView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
if (self.numberOfItems > 1) {
if (self.isCircle) {
//設(shè)置contentOffset為第二組第一個(gè)banner的位置
[_scrollView setContentOffset:CGPointMake(_pageSize.width * self.numberOfItems, 0) animated:NO];
self.page = self.numberOfItems;
[self startTimer];
} else {
[_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
self.page = self.numberOfItems;
}
}
}
break;
case KiraBannerTypeVertical: {
[self.scrollView setFrame:CGRectMake(0, 0, _pageSize.width, _pageSize.height)];
[self.scrollView setContentSize:CGSizeMake(0, _pageSize.height * _pageCount)];
_scrollView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
if (self.numberOfItems > 1) {
if (self.isCircle) {
[_scrollView setContentOffset:CGPointMake(_pageSize.height * self.numberOfItems, 0) animated:NO];
self.page = self.numberOfItems;
[self startTimer];
} else {
[_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
self.page = self.numberOfItems;
}
}
}
break;
default:
break;
}
_needsReload = NO;
}
[self setVisibleCellsAtContentOffset:_scrollView.contentOffset];
//refreshView是做cell在移動(dòng)過程中變化的函數(shù),下面會(huì)給出
[self refreshView];
}
3.在scrollViewDidScroll方法中對scrollView的contentOffset進(jìn)行判斷。由offset除以cell的寬度計(jì)算出當(dāng)前是第幾個(gè)cell。如果右滑超出第二組最后一個(gè)cell的范圍,就將offset設(shè)置到第二組第一個(gè)cell處,同理如果左滑超出第二組第一個(gè)cell,就將offset設(shè)置到第二組最后一個(gè)cell處,從而達(dá)到循環(huán)的效果。
case KiraBannerTypeHorizontal:
{
if (scrollView.contentOffset.x / _pageSize.width >= 2 * self.numberOfItems) {
[scrollView setContentOffset:CGPointMake(_pageSize.width * self.numberOfItems, 0) animated:NO];
self.page = self.numberOfItems;
}
if (scrollView.contentOffset.x / _pageSize.width <= self.numberOfItems - 1) {
[scrollView setContentOffset:CGPointMake((2 * self.numberOfItems - 1) * _pageSize.width, 0) animated:NO];
self.page = 2 * self.numberOfItems - 1;
}
}
break;
4.refreshView 在滑動(dòng)過程中根據(jù)offset做transform形變。
- (void)refreshView {
if (CGRectIsNull(self.scrollView.frame)) {
return;
}
switch (self.bannerType) {
case KiraBannerTypeHorizontal: {
CGFloat offset = _scrollView.contentOffset.x;
for (NSInteger i = self.visibleRange.location; i < self.visibleRange.location + self.visibleRange.length ; i++) {
UIView *cell = [self cellForIndex:i];
CGFloat origin = cell.frame.origin.x;
CGFloat delta = fabs(origin - offset);
CGRect originCellFrame = CGRectMake(_pageSize.width * i, 0, _pageSize.width, _pageSize.height);
//TODO:透明度漸變
if (delta < _pageSize.width) {
CGFloat leftRightInset = self.leftRightSpace * delta / _pageSize.width;
CGFloat topBottomInset = self.topBottomSpace * delta / _pageSize.width;
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-leftRightInset*2)/_pageSize.width,(_pageSize.height-topBottomInset*2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(topBottomInset, leftRightInset, topBottomInset, leftRightInset));
} else {
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-self.leftRightSpace * 2)/_pageSize.width,(_pageSize.height-self.topBottomSpace * 2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(self.topBottomSpace,
self.leftRightSpace,
self.topBottomSpace,
self.leftRightSpace));
}
}
}
break;
case KiraBannerTypeVertical: {
CGFloat offset = _scrollView.contentOffset.y;
for (NSInteger i = self.visibleRange.location; i < self.visibleRange.location + self.visibleRange.length ; i++) {
UIView *cell = [self cellForIndex:i];
CGFloat origin = cell.frame.origin.y;
CGFloat delta = fabs(origin - offset);
CGRect originCellFrame = CGRectMake(0, _pageSize.width * i, _pageSize.width, _pageSize.height);
//TODO:透明度漸變
if (delta < _pageSize.height) {
CGFloat leftRightInset = self.leftRightSpace * delta / _pageSize.height;
CGFloat topBottomInset = self.topBottomSpace * delta / _pageSize.height;
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-leftRightInset*2)/_pageSize.width,(_pageSize.height-topBottomInset*2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(topBottomInset, leftRightInset, topBottomInset, leftRightInset));
} else {
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-self.leftRightSpace * 2)/_pageSize.width,(_pageSize.height-self.topBottomSpace * 2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(self.topBottomSpace,
self.leftRightSpace,
self.topBottomSpace,
self.leftRightSpace));
}
}
}
break;
default:
break;
}
}
5 .自動(dòng)輪播。自動(dòng)輪播就是通過設(shè)置timer來控制自動(dòng)播放。其實(shí)自動(dòng)播放也是通過設(shè)置scrollview的contentOffset來實(shí)現(xiàn)。需要注意在stoptimer的時(shí)候?qū)ime置為nil,并且在合適的時(shí)機(jī)調(diào)用start及stoptimer方法。
- (void)startTimer {
if (self.numberOfItems > 1 && self.isAutoScroll && self.isCircle) {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.autoTime target:self selector:@selector(autoPlay) userInfo:nil repeats:YES];
self.timer = timer;
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
}
- (void)stopTimer {
[self.timer invalidate];
self.timer = nil;
}
- (void)autoPlay {
self.page ++;
switch (self.bannerType) {
case KiraBannerTypeHorizontal: {
[_scrollView setContentOffset:CGPointMake(self.page * _pageSize.width, 0) animated:YES];
}
break;
case KiraBannerTypeVertical: {
[_scrollView setContentOffset:CGPointMake(0, self.page * _pageSize.height) animated:YES];
}
break;
default:
break;
}
}
6.Cell的點(diǎn)擊回調(diào)。cell的點(diǎn)擊回調(diào)通過在fillPageAtIndex方法中,對cell添加UITapGestureRecognizer手勢,并且在@selector方法中,通過sender.view來拿到對應(yīng)的cell。然后通過objc_getAssociatedObject拿到該cell關(guān)聯(lián)的index進(jìn)行回調(diào)。
//在fillPageAtIndex函數(shù)中,完善以下代碼
UIView *cell = [self.dataSource kiraBanner:self viewForItemAtIndex:index % self.numberOfItems];
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapped:)];
[cell addGestureRecognizer:tap];
cell.userInteractionEnabled = YES;
- (void)cellTapped:(UITapGestureRecognizer *)sender {
UIView * cell = sender.view;
NSInteger index = -1;
NSNumber *value = objc_getAssociatedObject(cell, @selector(cellForIndex:));
if (value) {
index = value.integerValue % self.numberOfItems;
}
if ([self.delegate respondsToSelector:@selector(didSelectCell:inKiraBannerAtIndex:)]) {
[self.delegate didSelectCell:cell inKiraBannerAtIndex:index];
}
}
END
- 實(shí)現(xiàn)還有很多不完善的地方,也可能會(huì)存在一些bug,希望大家能及時(shí)指出,一起討論,共同進(jìn)步
- 這里是gayhub的地址