模仿微信適配 iPad 的佈局方式

wtfbuff發表於2019-05-10

首發於公眾號

微信在 iPad 上豎屏時顯示的樣式和手機版一樣,橫屏的顯示為分隔檢視。

UIKit 裡可以實現這樣的效果的元件是UISplitViewController

接下來就是要自定義一個 UISplitViewController 來逐步實現像微信一樣的效果。

豎屏時只顯示 Master 檢視

豎屏時 master 檢視需要佔滿全屏,橫屏的時候則 master 和 detail 都需要顯示,可以更好的利用 iPad 大螢幕的優勢。

豎屏模式下,設定 master 的寬度為全屏大小:

private func toPortraitWidth() {
  maximumPrimaryColumnWidth = maxMasterWidth
  preferredPrimaryColumnWidthFraction = 1
}
複製程式碼

橫屏時恢復為預設寬度

private func toLandscapeWidth() {
  maximumPrimaryColumnWidth = UISplitViewController.automaticDimension
  preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension
}
複製程式碼

處理子檢視的顯示

豎屏模式下,所有子檢視的顯示都由 master 來處理,

橫屏模式下,子檢視的顯示都放到 detail 檢視中,

需要實現下面這個代理方法,自己來控制頁面的顯示。

public func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
  if isPortrait {
    masterViewController?.show(vc, sender: nil)
  } else {
    detailViewController?.viewControllers = [vc]
  }

  return true
}
複製程式碼

處理橫豎屏切換

豎屏時,所有的頁面都顯示在 master 檢視中,

橫屏時,所有的子頁面都顯示在 detail 檢視中,

思路比較簡單,在 viewWillTransition 方法裡直接操作 viewControllers 屬性來達到移動子頁面的目的。

public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
  super.viewWillTransition(to: size, with: coordinator)

  var subVCs: [UIViewController] = masterViewController!.viewControllers

  // after transition, it will be portrait mode
  if !isPortrait {
    var flag: Bool = false

    if let topVC = detailViewController?.topViewController, !topVC.isKind(of: placeholderViewControllerClass) {
      subVCs.append(contentsOf: detailViewController!.viewControllers)
      flag = true
    }

    if flag {
      let placeholderViewController = (placeholderViewControllerClass as? UIViewController.Type)?.init() ?? UIViewController()

      detailViewController?.viewControllers = [placeholderViewController]
      masterViewController?.viewControllers = subVCs
    }

    toPortraitWidth()
  } else {
    if subVCs.count > 1 {
      subVCs.remove(at: 0)
      masterViewController!.popToRootViewController(animated: false)
      detailViewController?.viewControllers = subVCs
    }

    toLandscapeWidth()
  }
}
複製程式碼

SFSplitViewController

根據以上思路封裝了一個 SFSplitViewController 元件來實現像微信一樣的佈局功能。

使用起來也很簡單,把 SFSplitViewController 作為 RootController 就可以了,要求 master 和 detail 的容器必須是 UINavigationController 型別。

使用方法如下:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  let rootVC = SFSplitViewController(master: UINavigationController(rootViewController: MainViewController()),
                                           detail: UINavigationController(rootViewController: PlaceholderViewController()))
  rootVC.placeholderViewControllerClass = PlaceholderViewController.self

  window = UIWindow(frame: UIScreen.main.bounds)
  window?.rootViewController = rootVC
  window?.makeKeyAndVisible()

  return true
}
複製程式碼

完整的程式碼請參考我的 github: SFSplitViewController

img

相關文章