輪播視圖通常也叫Banner,90%以上App都會用到的一個控件,網上有很多開源代碼,但是至今我覺得比較好的一個是SDCycleScrollView,因為他解決了我接下來要吐槽的兩個問題。
通常實現定時自動滾動Banner的思路大體有三種:
3個`UIImageView`
N+2個`UIImageView`思路
N * section(個人不推薦,因為這將代碼寫死了,當有個無聊的人真的滾動到最後一個section時,程序就會crash了)
前兩種思路又分為用UIScrollView和UICollectionView實現,個人沒有用過第一種思路,都是第二種,本文也是基於第二種思路,這兩種思路的中心思想其實都是運用了視覺誤差。
具體思路請跳轉
中文
英文
快速滑動時卡頓
先來看看那些“垃圾”Banner
卡頓問題一(3個UIImageView思路)
通過卡頓頻率,我猜想這兩個項目的Banner思路應該一樣,用的三個UIImageView。
不知道你是否看得到動圖中卡頓的問題,如果你手機上恰好裝了這兩個App,可以自己試一下,很簡單,只要快速滑動就可以復現問題。
但是這兩個的PageControl還是處理得很好的,能實時滾動到相應的位置。
卡頓問題二((N+2)個UIImageView思路)
這個問題不好看出,因為他的卡頓頻率比較低,剛好是一組輪播視圖的周期。必須在第N+1張時才會復現。想看得清楚的小伙伴,如果自己項目Banner是這個思路可以測試一下自己項目的。
再看看這個PageControl的位置,在你快速滑動時,它是不動的,我猜想他控制PageControl的位置應該是在這個方法裡做的
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }
卡頓原因
就是這個兩個方法其中一個裡計算cell位置的判斷條件不對
func scrollViewDidScroll(_ scrollView: UIScrollView) { } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }
Tab切換卡中間,不能復位
由於這個問題比較難復現,我就用自己的Demo測試的
UICollectionView實現,會自動修復
UIScrollView實現,需手動修復
動圖中應該可以清楚的看到滾動視圖滾動的坐標不對。
原因
這個具體原因我也不知道,這是所有輪播都會發生的問題,我猜想是跟內部的RunLoop應該有關。
還有的Banner是pageControl和cell聯動不及時,比如鹹魚
因為是在這裡處理控制pageControl的位置的
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }
簡書Banner的pageControl向左手動拖動時又太靈敏。
func scrollViewDidScroll(_ scrollView: UIScrollView) { let page = scrollView.contentOffset.x / scrollView.frame.width if page <= 0.0 { // 向右拉 collectionView?.scrollToItem(at: IndexPath(item: urlStrs.count - 2, section: 0), at: .centeredHorizontally, animated: false) pageControl?.currentPage = urlStrs.count - 3 } else if page >= CGFloat(urlStrs.count - 1) { // 向左 pageControl?.currentPage = 0 collectionView?.scrollToItem(at: IndexPath(item: 1, section: 0), at: .centeredHorizontally, animated: false) } else { let value = page.truncatingRemainder(dividingBy: 1) < 0.5 if value { // cell過半才改變pageControl(簡書的Banner應該沒有這個判斷) pageControl?.currentPage = Int(page) - 1 } } }
推薦
UIScrollView 實踐經驗 詳細講了UIScrollView,並配有Demo
LazyScrollView來自天貓團隊,據說天貓首頁用的這個,有復雜UI的同學可以學習下
UITableView的Cell復用原理和源碼分析和LazyScrollView結合起來學習,肯定有很多收獲
最後附上修復以上問題的Demo