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

首發於公衆號git

微信在 iPad 上豎屏時顯示的樣式和手機版同樣,橫屏的顯示爲分隔視圖。github

UIKit 裏能夠實現這樣的效果的組件是UISplitViewControllerswift

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

豎屏時只顯示 Master 視圖

豎屏時 master 視圖須要佔滿全屏,橫屏的時候則 master 和 detail 都須要顯示,能夠更好的利用 iPad 大屏幕的優點。app

豎屏模式下,設置 master 的寬度爲全屏大小:ide

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

橫屏時恢復爲默認寬度佈局

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

處理子視圖的顯示

豎屏模式下,全部子視圖的顯示都由 master 來處理,ui

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

須要實現下面這個代理方法,本身來控制頁面的顯示。代理

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

img
相關文章
相關標籤/搜索