1. 程式人生 > >ScrollView自動佈局的實現方式

ScrollView自動佈局的實現方式

背景

開發中,可能會有一些頁面顯示的元素很多,可能會超出一個螢幕,但也不適合用 TableView 或者 CollectionView,此時我們一般會用 ScrollView,那麼就會出現自動佈局的問題。

實現方式

純程式碼

特點

  • 編碼繁瑣:需要手寫控制元件
  • 安全:只要正確地設定約束或者 frame、contentSize,一般不會出現滾動問題

示例

lazy var scrollView: UIScrollView = {
    let obj = UIScrollView(frame: CGRect(x: 0, y: 0, width: .screenW
, height: self.screenH)) return obj }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(scrollView) let subViewH: CGFloat = 400 let topView = UIView(frame: CGRect(x: 0, y: 0, width: enW, height: subViewH)) topView.backgroundColor = UIColor.red scrollView.addSubview
(topView) let bottomView = UIView(frame: CGRect(x: 0, y: subViewH, h: screenW, height: subViewH)) bottomView.backgroundColor = UIColor.purple scrollView.addSubview(bottomView) scrollView.contentSize = CGSize(width: screenW, height: iewH * 2) }

效果圖

scrollview_純程式碼實現.gif

Storyboard + 內部View

特點

  • 搭建介面簡單
  • 直觀
  • 需要佔位檢視

頁面結構如圖

Scrollview_SB_InnerView.png

可能出現的問題

  • ScrollView 中直接新增子元素,報錯:Has ambiguous scrollable content height
  • ScrollView 內容超出螢幕仍不能滾動
    Scrollview_layout_error.png

實現滾動的程式碼

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    let statusBarH: CGFloat = 20
    // 如果沒有導航欄,就返回狀態列的高度
    let navH = gationController?.navigationBar.frame.maxY ?? statusBarH
    let deltaH = (screenH - navH) - bottomView.frame.maxY
    placeholderViewBottomConstraint.constant = deltaH
}

效果圖

Scrollview_SB+InnerView.gif

Storyboard + 外部View

特點

  • 搭建介面簡單
  • 直觀
  • 不需要佔位檢視,不需要對 ScrollView 的佈局做特殊處理
  • 需要處理外部檢視的 frame(如果沒有使用者互動,可以忽略)

頁面結構如圖

Scrollview_SB+OutterView.png

可能出現的問題

  • ScrollView 中直接新增子元素,報錯:Has ambiguous scrollable content height
  • 當內容超出螢幕高度時,必須得設定 ContainerView 的 frame,否則不能滾動或者超出螢幕部分不接受事件
    Scrollview_SB+OutterView_事件問題.png

實現滾動的程式碼

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView.addSubview(containerView)
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    var f = containerView.frame
    f.size.width = screenW
    // 這句程式碼很重要,處理超出螢幕無法響應事件問題
    f.size.height = bottomView.frame.maxY
    containerView.frame = f
    scrollView.contentSize = CGSize(width: screenW, height: omView.frame.maxY)
}

效果圖

Scrollview_SB+OutterView.gif

總結

ScrollView 不能滾動的原因

  • contentSize 小於自身 frame 的尺寸
  • isScrollEnabled 屬性,不過它預設就是 true,預設無需設定
  • ScrollView 或者其父元素無法互動,此時我們需要檢查 isUserInteractionEnabled 屬性是否為 true

ScrollView 一直支援滾動

預設情況下,當 ScrollView 裡的元素不足一個螢幕高度時,不能滾動,如需滾動(彈簧效果),需要設定 alwaysBounceVertical 屬性為 true(水平方向亦如此)

關於 ScrollView 佈局的選擇

純程式碼佈局

如果是純程式碼佈局,只能用方式一。老老實實、一行一行程式碼實現佈局,雖然程式碼繁雜,但是坑少。(現在仍有不少公司是這樣程式設計的)

介面佈局

推薦方式三,這樣 ScrollView 和 其子元素分離,可以簡化很多約束問題,更直觀

以上程式碼,適用於 Swift 3.0 語法。