iOS 2D禀苦、3D無(wú)限輪播Banner矫俺,scrollView 自定義分頁(yè)

BSLoopView 實(shí)現(xiàn)了常用的 banner 無(wú)限循環(huán)輪播圖呻澜,支持 2D滥崩、3D 樣式

效果圖


Kapture 2020-10-19 at 11.12.49.gif
lo.gif

loo.gif

loop.gif

主要知識(shí)點(diǎn):

  • 無(wú)限輪播原理
  • 自動(dòng)輪播 timer 導(dǎo)致頁(yè)面無(wú)法釋放問(wèn)題
  • collectionView 自定義分頁(yè)大小及UICollectionViewFlowLayout其他問(wèn)題

1据忘、無(wú)限輪播原理

輪播原始數(shù)據(jù)為 NSArray *dataArr = @[1,2,3] 鹦牛,構(gòu)造新數(shù)據(jù),添加三次數(shù)據(jù)源

[self.newDataArr removeAllObjects];
[self.newDataArr addObjectsFromArray:dataArr];
[self.newDataArr addObjectsFromArray:dataArr];
[self.newDataArr addObjectsFromArray:dataArr];

新數(shù)據(jù)為 self.NewDataArr = @[1,2,3,1,2,3,1,2,3]

新數(shù)據(jù)構(gòu)造完成后若河,將collectionView的初始位置更改為中間的數(shù)據(jù)源起始位置,也就是第二個(gè)1的位置(下標(biāo)為3)

self.currentPageIndex = dataArr.count;

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath 
indexPathForRow:self.currentPageIndex inSection:0] 
atScrollPosition:UICollectionViewScrollPositionNone animated:NO];

這樣就確保了scrollVeiw的 兩邊都是有數(shù)據(jù)的能岩,我們要做的就是利用setContentOffset方法,讓 collectionView 始終展示中間的數(shù)據(jù)源即可
示例代碼

NSInteger newPageIndex = self.currentPageIndex;
            
if (self.currentPageIndex < self.dataArr.count) {
                
    newPageIndex = self.dataArr.count + self.currentPageIndex;
                
}else if (self.currentPageIndex >= self.dataArr.count*2){
                
    newPageIndex = self.currentPageIndex - self.dataArr.count;
}

計(jì)算了當(dāng)前頁(yè)面的pageIndex后萧福,通過(guò) pageIndex 計(jì)算實(shí)際偏移量拉鹃,然后 setContentOffset

※※※
為什么這里要用 setContentOffset ,而不用 scrollToItemAtIndexPath 呢鲫忍,因?yàn)槲以谑褂?scrollToItemAtIndexPath 發(fā)現(xiàn)如果 使用3d效果膏燕,就會(huì)出現(xiàn)UI錯(cuò)亂的問(wèn)題,使用3D效果+ scrollToItemAtIndexPath悟民,打印出來(lái)的偏移量發(fā)現(xiàn)并不正確坝辫,具體原因沒(méi)找到

2、自動(dòng)輪播 timer 導(dǎo)致頁(yè)面無(wú)法釋放問(wèn)題

如果 調(diào)用 scheduledTimerWithTimeInterval 方法執(zhí)行timer時(shí) 射亏,repeats:YES的話近忙,timer就會(huì)強(qiáng)持self,導(dǎo)致self無(wú)法釋放智润。一般情況下我們只要在需要的時(shí)候及舍,調(diào)用

[self.timer invalidate];
self.timer = nil;

就可以停止timer,然后釋放 self

但是很多時(shí)候窟绷,我們無(wú)法在確定的某個(gè)點(diǎn)去做 timer 的置空锯玛,所以我們需要使用其他方法,讓 timer 不在強(qiáng)持 self 兼蜈。

使用NSObject 類(lèi)提供的方法攘残,實(shí)現(xiàn)消息轉(zhuǎn)發(fā)可以解決此問(wèn)題

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel 

- (void)forwardInvocation:(NSInvocation *)invocation

具體做法:自定義一個(gè) 中間類(lèi),繼承NSObject为狸,然后引入 weak 聲明需要發(fā)送消息的對(duì)象

中間類(lèi) TimerTarget 如下:

@interface TimerTarget : NSObject

@property (nonatomic ,weak) BSLooperView * target;

@end
#pragma mark -
@implementation TimerTarget

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}
@end

我們?cè)诔跏蓟痶imer的時(shí)候 歼郭,將self 作為 TimerTarget 的target,然后將TimerTarget 作為timer的target 即可

self.timerTarget = [[TimerTarget alloc]init];
self.timerTarget.target = self;

self.timer = [NSTimer scheduledTimerWithTimeInterval:self.duration
 target:self.timerTarget selector:@selector(looperTime) userInfo:nil 
repeats:YES];

3辐棒、collectionView 自定義分頁(yè)大小及UICollectionViewFlowLayout其他問(wèn)題

  • 自定義分頁(yè)

自定義 UICollectionViewFlowLayout病曾,重寫(xiě) prepareLayout 方法 姊途,利用消息轉(zhuǎn)發(fā),重新設(shè)置頁(yè)面間距知态,頁(yè)面坐標(biāo)

/// collectionView 的 寬度 去掉 item 寬度
CGFloat contentInset = self.collectionView.width - self.itemSize.width;        
/// 減速模式
self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;
/// 算出內(nèi)邊距
self.collectionView.contentInset = UIEdgeInsetsMake(0, contentInset*0.5, 0, contentInset*0.5);
/// 設(shè)置每個(gè)頁(yè)面之間的間距
if ([self.collectionView respondsToSelector:NSSelectorFromString(@"_setInterpageSpacing:")]) {
   ((void(*)(id,SEL,CGSize))objc_msgSend)(self.collectionView,NSSelectorFromString(@"_setInterpageSpacing:"),CGSizeMake(-(contentInset-self.minimumLineSpacing), 0));
}
/// 設(shè)置 page 的坐標(biāo)(原理:正常坐標(biāo)是 0.0,如果想讓左邊留下 30 的寬度立叛,就需要 page 左移 30)
/// 左移如果想要 item 的邊距均分负敏,就需要 左移 contentInset*0.5
if ([self.collectionView respondsToSelector:NSSelectorFromString(@"_setPagingOrigin:")]) {
   ((void(*)(id,SEL,CGPoint))objc_msgSend)(self.collectionView,NSSelectorFromString(@"_setPagingOrigin:"),CGPointMake(-contentInset*0.5, 0));
}
  • layoutAttributesForElementsInRect 方法
    我們?cè)谥貙?xiě) layoutAttributesForElementsInRect 時(shí)
NSArray *originArr = [super layoutAttributesForElementsInRect:rect];

不能直接修改originArr數(shù)組內(nèi)容,需要將他copy后再返回

NSArray *originArr = [super layoutAttributesForElementsInRect:rect];
NSArray * array = [[NSArray alloc]initWithArray:originArr copyItems:YES];
for (UICollectionViewLayoutAttributes * attrs in array) {
   /// 修改
}

如果你的布局需要?jiǎng)討B(tài)更新秘蛇,則需要調(diào)用此方法

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
   return YES;
}

demo 下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末其做,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赁还,更是在濱河造成了極大的恐慌妖泄,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艘策,死亡現(xiàn)場(chǎng)離奇詭異蹈胡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)朋蔫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)罚渐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人驯妄,你說(shuō)我怎么就攤上這事荷并。” “怎么了青扔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵源织,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我微猖,道長(zhǎng)谈息,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任励两,我火速辦了婚禮黎茎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘当悔。我一直安慰自己傅瞻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布盲憎。 她就那樣靜靜地躺著嗅骄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饼疙。 梳的紋絲不亂的頭發(fā)上溺森,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天慕爬,我揣著相機(jī)與錄音,去河邊找鬼屏积。 笑死医窿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炊林。 我是一名探鬼主播姥卢,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼渣聚!你這毒婦竟也來(lái)了独榴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奕枝,失蹤者是張志新(化名)和其女友劉穎棺榔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體隘道,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡症歇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薄声。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片当船。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖默辨,靈堂內(nèi)的尸體忽然破棺而出德频,到底是詐尸還是另有隱情,我是刑警寧澤缩幸,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布壹置,位于F島的核電站,受9級(jí)特大地震影響表谊,放射性物質(zhì)發(fā)生泄漏钞护。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一爆办、第九天 我趴在偏房一處隱蔽的房頂上張望难咕。 院中可真熱鬧,春花似錦距辆、人聲如沸余佃。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)爆土。三九已至,卻和暖如春诸蚕,著一層夾襖步出監(jiān)牢的瞬間步势,已是汗流浹背氧猬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坏瘩,地道東北人盅抚。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像倔矾,于是被迫代替她去往敵國(guó)和親泉哈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353