iOS:一用就上癮的BottomSheetView

pujiaxin33發表於2018-08-05

專案中有類似於外賣軟體的已點菜品列表,類似於下圖:

meituan.gif

可以看到列表的顯示與隱藏,都只能通過按鈕觸發。不能通過手勢驅動。不能設定最小可顯示範圍。針對以上問題,就有了這個專案。

其實以上的需求核心問題就一個,如何優雅的解決:當內容還未到最大可顯示範圍時,列表裡的內容不能滾動;當內容顯示到最大的時候,如何不斷開當前滾動手勢,繼續滾動列表裡的內容。

之前寫了一個類似的底部列表滾動檢視,地址:https://github.com/pujiaxin33/JXBottomSheetTableView 裡面的實現方案還是挺有趣的,對外完全封裝了裡面的滾動控制細節,且以UITableView的子類實現。無奈越騷的操作越容易翻車。裡面的應用場景比較狹窄,需求一變動就GG了。 所以重新寫了這個庫,使用場景更大,使用更方便,互動更友善,好了,不說了,快上車吧!

原理

JXBottomSheetView新增一個UIPanGestureRecognizer,成為其delegate,並讓shouldRecognizeSimultaneouslyWithOtherGestureRecognizer方法返回true; 如此一來,內容承載檢視與列表檢視的滾動手勢可以同時響應了。接著,我們需要處理好當內容承載檢視未顯示到最大值時,列表檢視(UITableView、UICollectionView)的contentOffset.y會被強制設定為0,營造一種列表內容未滾動的假象; 當內容承載檢視滾動到最大的時候,就放開對列表檢視的滾動限制。 其他一些細節可以參看原始碼瞭解;

Github地址

github.com/pujiaxin33/…

特性

  • 支援長距離滾動,不斷手勢:當列表檢視滾動到規定的最高點時,停止檢視移動,轉而滾動裡面的內容;
  • 內容自適應:當列表的資料來源發生變動時,會根據最新的contentSize調整佈局;
  • 切換流暢:最大、最小的手勢切換,借鑑了系統UIScrollViewPagingEnabled切換效果;

預覽

  • 普通短距離滾動

NormalScroll.gif

  • 長距離滾動,手勢沒有停掉。滾動到頂部的時候,繼續滾動裡面的內容

Scroll 下午11.12.17.gif

  • 內容自適應,根據contentViewcontentSize自動調整佈局

Changed.gif

屬性/方法

屬性/方法 描述
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,而不是insertRowsdeleteRows重新整理頁面。因為...你試一下就知道了。

相關文章