專案中有類似於外賣軟體的已點菜品列表,類似於下圖:
可以看到列表的顯示與隱藏,都只能通過按鈕觸發。不能通過手勢驅動。不能設定最小可顯示範圍。針對以上問題,就有了這個專案。
其實以上的需求核心問題就一個,如何優雅的解決:當內容還未到最大可顯示範圍時,列表裡的內容不能滾動;當內容顯示到最大的時候,如何不斷開當前滾動手勢,繼續滾動列表裡的內容。
之前寫了一個類似的底部列表滾動檢視,地址:https://github.com/pujiaxin33/JXBottomSheetTableView 裡面的實現方案還是挺有趣的,對外完全封裝了裡面的滾動控制細節,且以UITableView的子類實現。無奈越騷的操作越容易翻車。裡面的應用場景比較狹窄,需求一變動就GG了。 所以重新寫了這個庫,使用場景更大,使用更方便,互動更友善,好了,不說了,快上車吧!
原理
為JXBottomSheetView
新增一個UIPanGestureRecognizer
,成為其delegate
,並讓shouldRecognizeSimultaneouslyWithOtherGestureRecognizer
方法返回true;
如此一來,內容承載檢視與列表檢視的滾動手勢可以同時響應了。接著,我們需要處理好當內容承載檢視未顯示到最大值時,列表檢視(UITableView、UICollectionView)的contentOffset.y
會被強制設定為0,營造一種列表內容未滾動的假象;
當內容承載檢視滾動到最大的時候,就放開對列表檢視的滾動限制。
其他一些細節可以參看原始碼瞭解;
Github地址
特性
- 支援長距離滾動,不斷手勢:當列表檢視滾動到規定的最高點時,停止檢視移動,轉而滾動裡面的內容;
- 內容自適應:當列表的資料來源發生變動時,會根據最新的
contentSize
調整佈局; - 切換流暢:最大、最小的手勢切換,借鑑了系統
UIScrollView
的PagingEnabled
切換效果;
預覽
- 普通短距離滾動
- 長距離滾動,手勢沒有停掉。滾動到頂部的時候,繼續滾動裡面的內容
- 內容自適應,根據
contentView
的contentSize
自動調整佈局
屬性/方法
屬性/方法 | 描述 |
---|---|
defaultMininumDisplayHeight | 預設最小內容高度,當contentSize.height更小時,會更新mininumDisplayHeight值。 |
defaultMaxinumDisplayHeight | 預設最大內容高度,當contentSize.height更小時,會更新maxinumDisplayHeight值。 |
displayState | 當前展示狀態,最大或最小 |
triggerDistance | 滾動多少距離,可以觸發展開和收縮狀態切換。 |
triggerVelocity | 觸發狀態切換的滾動速度,points/second |
contentView: UIScrollView | 用於承載內容的檢視,UITableView、UICollectionView皆可。 |
displayMax() | 顯示最大內容 |
displayMin() | 顯示最小內容 |
使用
tableView = UITableView.init(frame: CGRect.zero, style: .plain)
let bottomSheet = JXBottomSheetView(contentView: tableView)
bottomSheet.defaultMininumDisplayHeight = 100
bottomSheet.defaultMaxinumDisplayHeight = 300
bottomSheet.displayState = .minDisplay
bottomSheet.frame = self.view.bounds
view.addSubview(bottomSheet)
複製程式碼
注意
-
內部會影響到外部的程式碼
if let tableView = contentView as? UITableView { tableView.estimatedRowHeight = 0 } 複製程式碼
-
資料來源的增刪,請使用
reloadData
,而不是insertRows
、deleteRows
重新整理頁面。因為...你試一下就知道了。