iOS Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -

F01523d30d0f0b7c154914a886406bc4?s=47 Yuji Hato
September 13, 2018

iOS Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -

iOS Adaptive UI - To the optimum layout corresponding to devices and screen orientations with different resolutions -

F01523d30d0f0b7c154914a886406bc4?s=128

Yuji Hato

September 13, 2018
Tweet

Transcript

  1. 20.

    public protocol UITraitEnvironment : NSObjectProtocol { @available(iOS 8.0, *) public

    var traitCollection: UITraitCollection { get } @available(iOS 8.0, *) public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) } 4J[F$MBTTFT
  2. 21.

    open class UIView : UIResponder, NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment,

    UICoordinateSpace, UIFocusItem, CALayerDelegate { open class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer, UIFocusEnvironment { 4J[F$MBTTFT
  3. 22.

    public protocol UITraitEnvironment : NSObjectProtocol { @available(iOS 8.0, *) public

    var traitCollection: UITraitCollection { get } @available(iOS 8.0, *) public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) } 4J[F$MBTTFT
  4. 23.

    @available(iOS 8.0, *) open class UITraitCollection : NSObject, NSCopying, NSSecureCoding

    { open var userInterfaceIdiom: UIUserInterfaceIdiom { get } open var displayScale: CGFloat { get } open var horizontalSizeClass: UIUserInterfaceSizeClass { get } open var verticalSizeClass: UIUserInterfaceSizeClass { get } @available(iOS 9.0, *) open var forceTouchCapability: UIForceTouchCapability { get } @available(iOS 10.0, *) open var layoutDirection: UITraitEnvironmentLayoutDirection { get } @available(iOS 10.0, *) open var preferredContentSizeCategory: UIContentSizeCategory { get } @available(iOS 10.0, *) open var displayGamut: UIDisplayGamut { get } … } 4J[F$MBTTFT
  5. 24.

    @available(iOS 8.0, *) open class UITraitCollection : NSObject, NSCopying, NSSecureCoding

    { open var userInterfaceIdiom: UIUserInterfaceIdiom { get } open var displayScale: CGFloat { get } open var horizontalSizeClass: UIUserInterfaceSizeClass { get } open var verticalSizeClass: UIUserInterfaceSizeClass { get } @available(iOS 9.0, *) open var forceTouchCapability: UIForceTouchCapability { get } @available(iOS 10.0, *) open var layoutDirection: UITraitEnvironmentLayoutDirection { get } @available(iOS 10.0, *) open var preferredContentSizeCategory: UIContentSizeCategory { get } @available(iOS 10.0, *) open var displayGamut: UIDisplayGamut { get } … } 4J[F$MBTTFT
  6. 26.

    extension UITraitCollection { var isPortrait: Bool { return verticalSizeClass ==

    .regular && horizontalSizeClass == .compact } var isLandscape: Bool { return verticalSizeClass == .compact && horizontalSizeClass == .regular } var isCompactLandscape: Bool { return verticalSizeClass == .compact && horizontalSizeClass == .compact } var isRegularRegular: Bool { return verticalSizeClass == .regular && horizontalSizeClass == .regular } } 4J[F$MBTTFT
  7. 27.

    public protocol UITraitEnvironment : NSObjectProtocol { @available(iOS 8.0, *) public

    var traitCollection: UITraitCollection { get } @available(iOS 8.0, *) public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) } 4J[F$MBTTFT
  8. 30.

    4J[F$MBTTFT iPhone ॳظදࣔ viewDidLoad viewWillAppear traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear ճస࣌

    willTransition(to:with:) viewWillTransition(to:with:) traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews iPad ॳظදࣔ viewDidLoad viewWillAppear traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear ճస࣌ (traitCollection͕มߋͳ͍৔߹) viewWillTransition(to:with:) viewWillLayoutSubviews viewDidLayoutSubviews
  9. 31.

    4J[F$MBTTFT iPhone ॳظදࣔ viewDidLoad viewWillAppear traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear ճస࣌

    willTransition(to:with:) viewWillTransition(to:with:) traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews iPad ॳظදࣔ viewDidLoad viewWillAppear traitCollectionDidChange viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear ճస࣌ (traitCollection͕มߋͳ͍৔߹) viewWillTransition(to:with:) viewWillLayoutSubviews viewDidLayoutSubviews
  10. 32.
  11. 34.
  12. 35.

    1SBDUJDF 4UBDL7JFX 4DSPMM7JFX 4UBDL7JFX 7*FX 7*FX 7*FX -FGU7JFX *NBHF7JFX 4UBDL7JFX

    4DSPMM7JFX 4UBDL7JFX 7*FX 7*FX 7*FX -FGU7JFX *NBHF7JFX
  13. 36.
  14. 37.
  15. 38.
  16. 39.
  17. 40.
  18. 41.
  19. 44.

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if traitCollection.isPortrait {

    if rootStackView.arrangedSubviews.contains(leftView) { rootStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.insertArrangedSubview(leftView, at: 0) } } else { if scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !rootStackView.arrangedSubviews.contains(leftView) { rootStackView.insertArrangedSubview(leftView, at: 0) } } } 1SBDUJDF
  20. 45.

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if traitCollection.isPortrait {

    if rootStackView.arrangedSubviews.contains(leftView) { rootStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.insertArrangedSubview(leftView, at: 0) } } else { if scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !rootStackView.arrangedSubviews.contains(leftView) { rootStackView.insertArrangedSubview(leftView, at: 0) } } } 1SBDUJDF
  21. 46.

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if traitCollection.isPortrait {

    if rootStackView.arrangedSubviews.contains(leftView) { rootStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.insertArrangedSubview(leftView, at: 0) } } else { if scrollableStackView.arrangedSubviews.contains(leftView) { scrollableStackView.removeArrangedSubview(leftView) leftView.removeFromSuperview() } if !rootStackView.arrangedSubviews.contains(leftView) { rootStackView.insertArrangedSubview(leftView, at: 0) } } } 1SBDUJDF
  22. 47.
  23. 49.
  24. 50.
  25. 51.
  26. 52.
  27. 53.

    static func cellSize(isPortrait: Bool, parentSize: CGSize, isRegularRegular: Bool, safeArea: UIEdgeInsets)

    -> CGSize { let nextContentRatio: Double = 0.2 // νϥݟͤൺ཰ʢద౰ʣ let numberOfItems: Double = isPortrait ? 2 : 4 // (W:C, H:R͸)2ͭɺͦΕҎ֎͸4ͭ let numberOfItemsFactor: Double = numberOfItems + nextContentRatio let sideMargin: CGFloat = isRegularRegular ? 60 : 12 let cellSpace: CGFloat = 24 let margin = sideMargin + safeArea.left + safeArea.right let totalCellSpace: CGFloat = margin + cellSpace * CGFloat(numberOfItems) let remainWidth = parentSize.width - totalCellSpace let width = remainWidth / CGFloat(numberOfItemsFactor) let textAreaHeight: CGFloat = isRegularRegular ? 120 : 80 let thumbnailHeight = width / 16 * 9 let height = thumbnailHeight + textAreaHeight return CGSize(width: width, height: height) } 1SBDUJDF ے೑
  28. 54.

    static func cellSize(isPortrait: Bool, parentSize: CGSize, isRegularRegular: Bool, safeArea: UIEdgeInsets)

    -> CGSize { let nextContentRatio: Double = 0.2 // νϥݟͤൺ཰ʢద౰ʣ let numberOfItems: Double = isPortrait ? 2 : 4 // (W:C, H:R͸)2ͭɺͦΕҎ֎͸4ͭ let numberOfItemsFactor: Double = numberOfItems + nextContentRatio let sideMargin: CGFloat = isRegularRegular ? 60 : 12 let cellSpace: CGFloat = 24 let margin = sideMargin + safeArea.left + safeArea.right let totalCellSpace: CGFloat = margin + cellSpace * CGFloat(numberOfItems) let remainWidth = parentSize.width - totalCellSpace let width = remainWidth / CGFloat(numberOfItemsFactor) let textAreaHeight: CGFloat = isRegularRegular ? 120 : 80 let thumbnailHeight = width / 16 * 9 let height = thumbnailHeight + textAreaHeight return CGSize(width: width, height: height) } 1SBDUJDF
  29. 55.

    static func cellSize(isPortrait: Bool, parentSize: CGSize, isRegularRegular: Bool, safeArea: UIEdgeInsets)

    -> CGSize { let nextContentRatio: Double = 0.2 // νϥݟͤൺ཰ʢద౰ʣ let numberOfItems: Double = isPortrait ? 2 : 4 // (W:C, H:R͸)2ͭɺͦΕҎ֎͸4ͭ let numberOfItemsFactor: Double = numberOfItems + nextContentRatio let sideMargin: CGFloat = isRegularRegular ? 60 : 12 let cellSpace: CGFloat = 24 let margin = sideMargin + safeArea.left + safeArea.right let totalCellSpace: CGFloat = margin + cellSpace * CGFloat(numberOfItems) let remainWidth = parentSize.width - totalCellSpace let width = remainWidth / CGFloat(numberOfItemsFactor) let textAreaHeight: CGFloat = isRegularRegular ? 120 : 80 let thumbnailHeight = width / 16 * 9 let height = thumbnailHeight + textAreaHeight return CGSize(width: width, height: height) } 1SBDUJDF
  30. 56.

    static func cellSize(isPortrait: Bool, parentSize: CGSize, isRegularRegular: Bool, safeArea: UIEdgeInsets)

    -> CGSize { let nextContentRatio: Double = 0.2 // νϥݟͤൺ཰ʢద౰ʣ let numberOfItems: Double = isPortrait ? 2 : 4 // (W:C, H:R͸)2ͭɺͦΕҎ֎͸4ͭ let numberOfItemsFactor: Double = numberOfItems + nextContentRatio let sideMargin: CGFloat = isRegularRegular ? 60 : 12 let cellSpace: CGFloat = 24 let margin = sideMargin + safeArea.left + safeArea.right let totalCellSpace: CGFloat = margin + cellSpace * CGFloat(numberOfItems) let remainWidth = parentSize.width - totalCellSpace let width = remainWidth / CGFloat(numberOfItemsFactor) let textAreaHeight: CGFloat = isRegularRegular ? 120 : 80 let thumbnailHeight = width / 16 * 9 let height = thumbnailHeight + textAreaHeight return CGSize(width: width, height: height) } 1SBDUJDF
  31. 59.
  32. 60.

    override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? { if UIDevice.current.userInterfaceIdiom

    == .pad, let rootViewController = UIApplication.shared.keyWindow?.rootViewController { let portraitTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .regular)]) let landscapeTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .compact)]) let rootViewSize = rootViewController.view.bounds.size let size = view.bounds.size if isMultiTasking(rootViewSize: rootViewSize) { if rootViewController.traitCollection.isRegularRegular { return landscapeTraitCollection } else { return portraitTraitCollection } } else if size.width > size.height { return landscapeTraitCollection } else { return portraitTraitCollection } } return traitCollection } 1SBDUJDF
  33. 61.

    override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? { if UIDevice.current.userInterfaceIdiom

    == .pad, let rootViewController = UIApplication.shared.keyWindow?.rootViewController { let portraitTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .regular)]) let landscapeTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .compact)]) let rootViewSize = rootViewController.view.bounds.size let size = view.bounds.size if isMultiTasking(rootViewSize: rootViewSize) { if rootViewController.traitCollection.isRegularRegular { return landscapeTraitCollection } else { return portraitTraitCollection } } else if size.width > size.height { return landscapeTraitCollection } else { return portraitTraitCollection } } return traitCollection } 1SBDUJDF
  34. 62.

    override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? { if UIDevice.current.userInterfaceIdiom

    == .pad, let rootViewController = UIApplication.shared.keyWindow?.rootViewController { let portraitTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .regular)]) let landscapeTraitCollection = UITraitCollection(traitsFrom: [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .compact)]) let rootViewSize = rootViewController.view.bounds.size let size = view.bounds.size if isMultiTasking(rootViewSize: rootViewSize) { if rootViewController.traitCollection.isRegularRegular { return landscapeTraitCollection } else { return portraitTraitCollection } } else if size.width > size.height { return landscapeTraitCollection } else { return portraitTraitCollection } } return traitCollection } 1SBDUJDF
  35. 63.
  36. 64.
  37. 73.
  38. 75.