SlideShare une entreprise Scribd logo
1  sur  75
Adaptive UI
解像度の異なるデバイスや画面の向きに対応する
最適なレイアウトへ
Yuji Hato
俺コン 2018 Summer / Day. 2
Yuji Hato
CyberAgent, Inc. / AbemaTV, Inc.
dekatotoro
@dekatotoro
Contributed services
About me
Adaptive UI
Size Clases
AbemaTVの対応例
Practice
Agenda
Adaptive UI
Adaptive UI
https://developer.apple.com/videos/play/wwdc2016/222/
Device Size
https://developer.apple.com/videos/play/wwdc2016/222/
Adaptive UI
Device Size × Direction
https://developer.apple.com/videos/play/wwdc2016/222/
Adaptive UI
Device Size × Direction × Multitasking
https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/
Adaptive UI
Device Size
https://developer.apple.com/videos/play/wwdc2016/233/
Adaptive UI
Device Size × Direction × Multitasking
デバイスのサイズや向き、状態に合わせて
最適なレイアウトにする
Adaptive UI
Size Classes
Size Classes
https://developer.apple.com/videos/play/wwdc2016/222/
Compact × Reqular 4 pattern
Size Classes
https://developer.apple.com/videos/play/wwdc2016/222/
Compact × Reqular 4 pattern
Size Classes
https://developer.apple.com/videos/play/wwdc2016/233/
Device Size × Direction × Multitasking
Size Classes
https://developer.apple.com/videos/play/wwdc2016/233/
Apply to size class
https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/
Size Classes
Definition
https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/
Size Classes
Definition for Multitasking
https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/AdoptingMultitaskingOniPad/QuickStartForSlideOverAndSplitView.html#//apple_ref/doc/uid/TP40015145-
CH13-SW3
Size Classes
Definition for Multitasking
https://developer.apple.com/videos/play/wwdc2016/222/
Size Classes
Many combinations → 4 pattern
public protocol UITraitEnvironment : NSObjectProtocol {
@available(iOS 8.0, *)
public var traitCollection: UITraitCollection { get }
@available(iOS 8.0, *)
public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
}
Size Classes
open class UIView : UIResponder, NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem,
UITraitEnvironment, UICoordinateSpace, UIFocusItem, CALayerDelegate {
open class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment,
UIContentContainer, UIFocusEnvironment {
Size Classes
public protocol UITraitEnvironment : NSObjectProtocol {
@available(iOS 8.0, *)
public var traitCollection: UITraitCollection { get }
@available(iOS 8.0, *)
public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
}
Size Classes
@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 }
…
}
Size Classes
@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 }
…
}
Size Classes
Size Classes
https://developer.apple.com/videos/play/wwdc2016/222/
Compact × Reqular 4 pattern
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
}
}
Size Classes
public protocol UITraitEnvironment : NSObjectProtocol {
@available(iOS 8.0, *)
public var traitCollection: UITraitCollection { get }
@available(iOS 8.0, *)
public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
}
Size Classes
https://developer.apple.com/videos/play/wwdc2014/216/
Size Classes
https://developer.apple.com/videos/play/wwdc2014/216/
Size Classes
Size Classes
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
Size Classes
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
Practice
UITraitCollectionの変化によるlayout
変更
Practice
Practice
Practice
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
Practice
Practice
Practice
Practice
Practice
Practice
scrollが下のみになる
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
Practice
全てScrollさせたい
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
Practice
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)
}
}
}
Practice
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)
}
}
}
Practice
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)
}
}
}
Practice
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
StackView
ScrollView
StackView
VIew
VIew
VIew
LeftView
ImageView
Practice
Size変化によるlayout変更
Practice
Practice
Practice
Practice
Practice
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)
}
Practice
筋肉
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)
}
Practice
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)
}
Practice
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)
}
Practice
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionView.reloadData()
}
Practice
iPadの縦横で異なるレイアウトにする
Practice
Practice
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
}
Practice
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
}
Practice
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
}
Practice
Practice
Practice
AbemaTVの対応例
AbemaTVの対応例
iPhone
AbemaTVの対応例
iPhone
AbemaTVの対応例
iPhone
AbemaTVの対応例
iPad
AbemaTVの対応例
iPad
AbemaTVの対応例
UISplitViewController
AbemaTVの対応例
iPhone iPad
まとめ
まとめ
Size ClassとTrait Collectionを理解する
Auto Layout × Size Class × UIStackView × 筋肉
開発・メンテナンス工数は増加するので事業的観点も重要
Thank you

Contenu connexe

Tendances

システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方Chihiro Ito
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門増田 亨
 
こわくない Git
こわくない Gitこわくない Git
こわくない GitKota Saito
 
Unityで始めるバーチャルプロダクション
Unityで始めるバーチャルプロダクションUnityで始めるバーチャルプロダクション
Unityで始めるバーチャルプロダクションUnity Technologies Japan K.K.
 
シリコンバレー流開発スタイル
シリコンバレー流開発スタイルシリコンバレー流開発スタイル
シリコンバレー流開発スタイルKohei Taniguchi
 
Git & ブランチモデルで学ぶ バージョン管理入門
Git & ブランチモデルで学ぶ バージョン管理入門Git & ブランチモデルで学ぶ バージョン管理入門
Git & ブランチモデルで学ぶ バージョン管理入門kazuki kuriyama
 
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~UnityTechnologiesJapan002
 
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Yahoo!デベロッパーネットワーク
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/PrismNaoki Aoyama
 
モバイルアプリの高速で安定したビルドを支えるJenkins運用術
モバイルアプリの高速で安定したビルドを支えるJenkins運用術モバイルアプリの高速で安定したビルドを支えるJenkins運用術
モバイルアプリの高速で安定したビルドを支えるJenkins運用術KLab Inc. / Tech
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているKoichi Tanaka
 
Web ブラウザで DRM
Web ブラウザで DRMWeb ブラウザで DRM
Web ブラウザで DRMYusuke Goto
 
知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について健一 辰濱
 
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!Unity Technologies Japan K.K.
 
Top Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 JpTop Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 JpKenji Hiranabe
 
JIRA / Confluence の 必須プラグインはこれだ
JIRA / Confluence の必須プラグインはこれだJIRA / Confluence の必須プラグインはこれだ
JIRA / Confluence の 必須プラグインはこれだNarichika Kajihara
 
Task and Time monitoring with Backlog and Toggl
Task and Time monitoring with Backlog and TogglTask and Time monitoring with Backlog and Toggl
Task and Time monitoring with Backlog and TogglYukiya Hayashi
 
go generate 完全入門
go generate 完全入門go generate 完全入門
go generate 完全入門yaegashi
 

Tendances (20)

システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 
Unityで始めるバーチャルプロダクション
Unityで始めるバーチャルプロダクションUnityで始めるバーチャルプロダクション
Unityで始めるバーチャルプロダクション
 
SwiftのDI方法につい て最近考えてた話
SwiftのDI方法につい て最近考えてた話SwiftのDI方法につい て最近考えてた話
SwiftのDI方法につい て最近考えてた話
 
Leap motion.js
Leap motion.jsLeap motion.js
Leap motion.js
 
シリコンバレー流開発スタイル
シリコンバレー流開発スタイルシリコンバレー流開発スタイル
シリコンバレー流開発スタイル
 
Git & ブランチモデルで学ぶ バージョン管理入門
Git & ブランチモデルで学ぶ バージョン管理入門Git & ブランチモデルで学ぶ バージョン管理入門
Git & ブランチモデルで学ぶ バージョン管理入門
 
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
 
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/Prism
 
モバイルアプリの高速で安定したビルドを支えるJenkins運用術
モバイルアプリの高速で安定したビルドを支えるJenkins運用術モバイルアプリの高速で安定したビルドを支えるJenkins運用術
モバイルアプリの高速で安定したビルドを支えるJenkins運用術
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
 
Web ブラウザで DRM
Web ブラウザで DRMWeb ブラウザで DRM
Web ブラウザで DRM
 
知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について
 
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
 
Top Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 JpTop Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 Jp
 
JIRA / Confluence の 必須プラグインはこれだ
JIRA / Confluence の必須プラグインはこれだJIRA / Confluence の必須プラグインはこれだ
JIRA / Confluence の 必須プラグインはこれだ
 
Task and Time monitoring with Backlog and Toggl
Task and Time monitoring with Backlog and TogglTask and Time monitoring with Backlog and Toggl
Task and Time monitoring with Backlog and Toggl
 
go generate 完全入門
go generate 完全入門go generate 完全入門
go generate 完全入門
 

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

Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015 Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015 Mario Jorge Pereira
 
iOS Development For Android Developers
iOS Development For Android DevelopersiOS Development For Android Developers
iOS Development For Android DevelopersDarryl Bayliss
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
Android development for iOS developers
Android development for iOS developersAndroid development for iOS developers
Android development for iOS developersDarryl Bayliss
 
3D Touch: Preparando sua app para o futuro do iOS
3D Touch: Preparando sua app para o futuro do iOS3D Touch: Preparando sua app para o futuro do iOS
3D Touch: Preparando sua app para o futuro do iOSRodrigo Borges
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in AndroidRobert Cooper
 
Adopting 3D Touch in your apps
Adopting 3D Touch in your appsAdopting 3D Touch in your apps
Adopting 3D Touch in your appsJuan C Catalan
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael Galpin
 
Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Alfredo Morresi
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsScott Gardner
 
Rambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRAMBLER&Co
 
Manual Layout Revisited
Manual Layout RevisitedManual Layout Revisited
Manual Layout Revisitedgillygize
 
Navigation Architecture Component(京都Devかふぇ バージョン)
Navigation Architecture Component(京都Devかふぇ バージョン)Navigation Architecture Component(京都Devかふぇ バージョン)
Navigation Architecture Component(京都Devかふぇ バージョン)Yasutaka Kawamoto
 
What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018Somkiat Khitwongwattana
 
Getting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUIGetting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUIScott Gardner
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidDaniel Baccin
 

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

Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015 Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015
 
iOS Development For Android Developers
iOS Development For Android DevelopersiOS Development For Android Developers
iOS Development For Android Developers
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
What's new in iOS9
What's new in iOS9What's new in iOS9
What's new in iOS9
 
Android 3
Android 3Android 3
Android 3
 
Android development for iOS developers
Android development for iOS developersAndroid development for iOS developers
Android development for iOS developers
 
3D Touch: Preparando sua app para o futuro do iOS
3D Touch: Preparando sua app para o futuro do iOS3D Touch: Preparando sua app para o futuro do iOS
3D Touch: Preparando sua app para o futuro do iOS
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
 
Adopting 3D Touch in your apps
Adopting 3D Touch in your appsAdopting 3D Touch in your apps
Adopting 3D Touch in your apps
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)
 
Action bar
Action barAction bar
Action bar
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the Things
 
Rambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуй
 
Manual Layout Revisited
Manual Layout RevisitedManual Layout Revisited
Manual Layout Revisited
 
Navigation Architecture Component(京都Devかふぇ バージョン)
Navigation Architecture Component(京都Devかふぇ バージョン)Navigation Architecture Component(京都Devかふぇ バージョン)
Navigation Architecture Component(京都Devかふぇ バージョン)
 
What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018
 
Getting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUIGetting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUI
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
 

Plus de Yuji Hato

継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」Yuji Hato
 
iOSDC 2018 動画をなめらかに動かす技術
iOSDC 2018 動画をなめらかに動かす技術iOSDC 2018 動画をなめらかに動かす技術
iOSDC 2018 動画をなめらかに動かす技術Yuji Hato
 
5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSourcesYuji Hato
 
AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話Yuji Hato
 
Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Yuji Hato
 
AbemaTV on tvOS
AbemaTV on tvOSAbemaTV on tvOS
AbemaTV on tvOSYuji Hato
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwiftYuji Hato
 
CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状Yuji Hato
 
AWA with Realm
AWA with RealmAWA with Realm
AWA with RealmYuji Hato
 

Plus de Yuji Hato (9)

継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
 
iOSDC 2018 動画をなめらかに動かす技術
iOSDC 2018 動画をなめらかに動かす技術iOSDC 2018 動画をなめらかに動かす技術
iOSDC 2018 動画をなめらかに動かす技術
 
5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources
 
AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話
 
Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017
 
AbemaTV on tvOS
AbemaTV on tvOSAbemaTV on tvOS
AbemaTV on tvOS
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwift
 
CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状
 
AWA with Realm
AWA with RealmAWA with Realm
AWA with Realm
 

Dernier

WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 

Dernier (20)

WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 

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

Notes de l'éditeur

  1. アジェンダでですが、 まず最初にAdaptive UIとsizeクラスについて説明して、その後にいくつか実装例を紹介して 最後にAbemaTVの対応例を紹介したいと思います。
  2. まず adaptiveUIについてですが
  3. iPhone iPad含めて色々なサイズのデバイスがあります。 ちょうど今朝、iPhone XS(テンエス)」「iPhone XS Max(テンエス マックス)」「iPhone XR(テンアール)なんかも発表されてされ今後さらに増えていくことが予想されます
  4. で、デバイスの向きも含めると、さらにこう増えていって
  5. iPadのマルチタスキングも含めるとかなりのパターンになります
  6. iPad pro 12.9inchは2048px × 2732px, 10.5inchは1668px × 2224pxだったりと 様々デバイスのサイズがあることがわかります。
  7. 図にするとこんな感じで、デバイスの状態やサイズと向きを整理できます。
  8. Adaptive UIとはなんなのかということですが、簡単に言うと紹介したような様々なデバイスの状態や、サイズや向きに合わせて最適なレイアウトにしてくださいということになると思います。
  9. そこで必要になるのがsize classになります
  10. サイズクラスはhorizontalとverticalがあり、compact, regularの 組み合わせで表現され組み合わせで4パータンになります widthとheightがcompact compactのもの、widthがRegular、heightがcompactのもの、 widthとcompactがheightがregularのもの、widthとheightがregular regularのもので4パターンです
  11. widthとheightがcompactのものがiPhoneのplus以外の横、 widthがRegular、heightがcompactのものが iPhone plus系の横、 widthとcompact、heightがregularが通常のiPhoneの縦 widthとheightがregularがiPadの縦/横 といった感じです
  12. 先程のデバイスサイズと向きのパターン図ですが、これに当てはめると
  13. この図のように当てはめられて、iPhone plus系がwidthがRegularでheightがcompact、iPhone plus系以外の横がcompact × compactなのも納得できるかと思います。
  14. それぞれのデバイスの種類と向きに対してsize classが定義されています。
  15. Multitasking時のsize classも定義されていて、一覧だと分かりづらいですが
  16. このようにiPad通常時はregular × regular、multitasking時の 2/3, 1/2, 1/3 のときのサイズクラスの状態が定義されています。
  17. 結局何が言いたかったかというと、Size Classとは デバイスと向きと状態によって多くの組み合わせがあるけど、それを4パターンで表現しようという
  18. codeではどのようになるのかということですが、 Size classで重要になるのがUITrait でUITraitEnvironmentプロトコルが定義されています
  19. UITraitEnvironmentはUIViewとUIViewControllerが適応していて
  20. UITraitCollectionから見ていくと
  21. UITraitCollectionはそのデバイスの特性情報を保持していて、UIUserInterfaceIdiomはiPhone, iPad, tv, carplayなのかが取得できたり、displayScaleが取得できたり、size classもこのクラスから取得します。あとはforceTouchCapabilityで3DTouchが使えるのかなどデバイスの特性を扱うクラスになります。
  22. この中で今回sizeClassにフォーカスします。 先程説明しましたが、horizontalSizeClassとverticalSizeClassがありまして、
  23. 先程の4パターン組み合わせの図をコードにすると
  24. このような感じで 通常のiPhone縦のisPortrait、iPhone plus系の横のlandscape、plus系以外のiPhone横のcompactLandscape、iPadのregular regularの4つですね
  25. 次にtraitCollectionDidChangeですが、これはtraitCollectionが決定したときと、変化したときに呼ばれます
  26. overideしてtraitCollectionが決定したときや、変化したときに処理を書くことができます。UIScreenからUIWindow、UIViewController, UIViewと伝播されていきます。
  27. イメージとしては、willTransitionというtraitCollectionが変化したときに呼ばれるUIContentContainerのmethodがあるのですが、これが呼ばれたあとにtraitCollectionDidChangeがきます。
  28. ViewControllerのライフサイクルメソッドと並べるとこのようになります。
  29. 初期表示ですが、viewDidLoad viewWillAppearのあとにtraitCollectionDidChangeがきてtraitCollectionが決定します。その後viewWillLayoutSubviews, didLayoutSubviews, viewDidAppearとなります。回転時ですが、willTransition, viewWillTransition, traitCollectionDidChange, viewWillLayoutSubviewsの順に呼ばれます。 Ipadの場合は回転してもtraitCollectionの変化がないので、willTransitionとtraitCollectionDidChangeは呼ばれません。viewWillTransitionはviewのsizeの変更で呼ばれるのでiPadでも呼ばれる動作となります
  30. はい、ここから具体的な例で説明したいと思います。
  31. まず、最初にtraitCollectionの変化によるレイアウト変更で
  32. iPhoneの縦と横でこのようなUIを作りたい場合の例になります。 みなさんこれどうやってつくりますか?
  33. 作り方は色々あると思うのですが、わたしはこのように作りました。 縦の場合はStackViewにLeftViewとScrollableなStackViewをverticalに並べる、横の場合はstackViewにleftViewとScrollableなStackViewをhorizontalに並べる形にしました。
  34. こちらInterfaceBuilderで全て定義できます。これは縦の場合で、
  35. こちら横の場合ですが
  36. まずrootのstackViewのaxisをsizeClassの組み合わせで定義できるのでwidthがcompact、heightがRegularのiPhone縦の場合はverticalでそれ以外はhorizontalにしています。
  37. あとはiPhone縦以外の場合のサイズクラスでLeftViewと右のScrollableなstackViewの比率を2:5で定義します
  38. 他にもサイズクラスに応じていくつか制約を定義していますが細かいので割愛してですね、下のpainでそれぞれ端末や向きでの状態にして確認することができます
  39. これはIpadの縦横とマルチタスキングの確認の例ですが、できる限りInterfaceBuilderでレイアウトしたほうが確認が楽になります。
  40. このままだとひとつ問題あって、縦の場合下しかスクロースしない状態になります。
  41. 縦の場合全てスクロールしたい場合は、コードで書く必要があります
  42. 先程の説明したtraitCollectionDidChangeをoverrideして実装を入れます
  43. portraitの場合はrootのstackViewからLeftViewをremoveしてscrollableStackViewにinsertします。
  44. portraitでない場合はscrollableStackViewからleftViewを削除してrootのstackViewにinsertします
  45. そうするとレイアウト変化が、このように縦のときはRootStackViewのなかにScrollableなStackViewが入り、横のときはLeftViewとScrollableStackViewが分離するといった形にできます
  46. 次に画面サイズ変更によるサイズ変更
  47. このようなレイアウトを作成する場合を例にします。 StackView × StackView と TableView× CollectionViewなど作り方は色々ありますが CollectionViewにCollectionViewを入れて作った例になります
  48. 縦のときはコレクション2つプラスチラ見せ、横のときはコレクション4つプラスチラ見せというデザイン要望として
  49. iPadは縦横でこのような感じで
  50. Regular Regularなので4つ表示で縦横で個数は一緒で、コレクションのサイズを画面合図に合わせる形になります
  51. 結論からいうと、筋肉になります
  52. チラ見せ比率を0.2と適当に定義して portraitのときはアイテム2, それ以外はアイテム4つとします nextContentRatioを足して
  53. safeAreaも考慮して、marginを計算して、 viewの幅からコレクションの幅を決定します
  54. 幅が決まったところで、この例だと画像を16:9で高さを計算して テキストの高さを決めてサイズとしています
  55. で、先程でてきたサイズ変更時に呼ばれるviewWillTransitionでcollectionViewをreloadDataするなどで再計算してレイアウトを変更しています
  56. 最後のpracticeですがiPadで縦横で異なるレイアウトにしてみる例になります
  57. 最初の例にした画面ですが、iPadはどちらもRegular Regularなので縦と横で同じレイアウトになるのですが、
  58. OverrideTraitCollectionでtraitCollectionをoverrideできるのでそこでiPadの場合にtraitCollectionを変更してあげることで、縦横のレイアウト変更を行うことができあす
  59. まずportraitとcompact, comapctのlandscape traitCollectionを定義して
  60. MultiTasking時はRegular Regularならlandscape扱い、 それ以外はportrait扱い MultiTaskingじゃないときはviewのwidthが大きいときはlandscape扱い、heightの方が大きい場合はportrait扱いにoverrideします。 UIScreen.main.bounds.size のサイズはスクリーンサイズになってしまっているのでrootViewControllerから取得
  61. そうするとこのようにiPadの縦と横でレイアウト変更が可能になります
  62. MultiTaskingの場合もそのときのサイズクラスに合わせてレイアウト変更が可能になります
  63. 最後にAbemaTVでの対応例について少し紹介します
  64. これはテレビの画面ですが、縦と横で大きくレイアウトを変更しています。 縦の場合は番組表リストも閲覧できるようにして、横の場合は視聴を優先するレイアウトにしています
  65. こちらは縦のとき画像テキストで縦の並びですが、横の場合は画像テキストで横の並びにする工夫をしています。
  66. 再生プレイヤーは縦の場合は、動画の下に情報を出して、横の場合はフルスクリーンモードと情報を見れる2つのモードを用意しています
  67. iPadの場合も同様に縦と横でレイアウト変更を行っています
  68. マルチタスキングの場合もそれぞれのサイズクラスに合わせてレイアウト変更しています
  69. あとは今回紹介できませんでしたが、サイズクラスによってMasterとDetailの構成が変化するUISplitViewControllerも設定画面で使っていました。
  70. iPhoneのときはスライドメニューにしていますが、実はiPadの場合はタブメニューにするという荒業もやっています
  71. はい、まとめです。
  72. 1つ目Adaptive UIに対応するにはSize Classと TraitCollectionがキモになるということと、 2つ目は、レイアウトはそれぞれ組み方が異なるかと思いますが、Auto Laout と Size Class と UIStackView をうまく組み合わせてつくるのが良いかなと個人的には思っていて、プラス筋肉が必要になるケースもありますということと、あと最後ですが実際AbemaTVで対応していて、動画サービスは横とかなり相性良いので対応していますが、かなり工数は膨らむので、費用対効果で事業的な観点も必要かなと思っています