Pro Yearly is on sale from $80 to $50! »

Apple TV - tvOS入門 -

F01523d30d0f0b7c154914a886406bc4?s=47 Yuji Hato
September 17, 2017

Apple TV - tvOS入門 -

Apple TV Introduction to tvOS

F01523d30d0f0b7c154914a886406bc4?s=128

Yuji Hato

September 17, 2017
Tweet

Transcript

  1. iOSDC 2017/09/17 Yuji Hato Apple TV tvOSೖ໳

  2. About me Yuji Hato CyberAgent, Inc. / AbemaTV, Inc. dekatotoro

    @dekatotoro Contributed services
  3. Apple TV

  4. Apple TV

  5. ・64-bit A8 processor ・32GB or 64GB of storage ・2GB of

    RAM ・10/100Mbps Ethernet ・WiFi 802.11a/b/g/n/ac ・1080p resolution ・HDMI 1.4 Apple TV 4th generation ・A10X Fusion ・32GB or 64GB of storage ・3GB of RAM ・Gigabit Ethernet ・Wi-Fi with MIMO 802.11ac ・2160p resolution ・HDMI 2.0 4K
  6. 32GB 15,800円 64GB 20,800円 ※2016/09に値下げ ・32GB 18,400円 →15,800円(2,600円値下げ) ・64GB 24,800円

    →20,800円(4,000円値下げ) Apple TV (tvOS) 4th generation 4K 32GB 19,800円 64GB 21,800円
  7. Remote

  8. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

  9. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

  10. Swipe Click Tap IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

  11. Development Method

  12. Development Method iOSとほぼ同様に開発 ɾTraditional Apps TVMLとTVJSをで開発 ɾClient-Server Apps

  13. Limited App Size

  14. Limited App Size 200MB 4GB

  15. Data Storage

  16. Limited Local Storage 4FSWJDF 0OMJOF-PDBM 1FSTJTUFOU 5FNQPSBSZ MJNJU J$MPVE,FZ7BMVF 4UPSF

    ,74 0OMJOF 1FSTJTUFOU .#NBY $MPVE,JU 0OMJOF 1FSTJTUFOU  6TFS%FGBVMUT -PDBM 1FSTJTUFOU ,#NBY ,FZDIBJO -PDBM 1FSTJTUFOU  $BDIF%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE 5FNQPSBSZ%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE
  17. Limited Local Storage 4FSWJDF 0OMJOF-PDBM 1FSTJTUFOU 5FNQPSBSZ MJNJU J$MPVE,FZ7BMVF 4UPSF

    ,74 0OMJOF 1FSTJTUFOU .#NBY $MPVE,JU 0OMJOF 1FSTJTUFOU  6TFS%FGBVMUT -PDBM 1FSTJTUFOU ,#NBY ,FZDIBJO -PDBM 1FSTJTUFOU  $BDIF%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE 5FNQPSBSZ%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE
  18. Limited Local Storage 4FSWJDF 0OMJOF-PDBM 1FSTJTUFOU 5FNQPSBSZ MJNJU J$MPVE,FZ7BMVF 4UPSF

    ,74 0OMJOF 1FSTJTUFOU .#NBY $MPVE,JU 0OMJOF 1FSTJTUFOU  6TFS%FGBVMUT -PDBM 1FSTJTUFOU ,#NBY ,FZDIBJO -PDBM 1FSTJTUFOU  $BDIF%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE 5FNQPSBSZ%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE
  19. Limited Local Storage 4FSWJDF 0OMJOF-PDBM 1FSTJTUFOU 5FNQPSBSZ MJNJU J$MPVE,FZ7BMVF 4UPSF

    ,74 0OMJOF 1FSTJTUFOU .#NBY $MPVE,JU 0OMJOF 1FSTJTUFOU  6TFS%FGBVMUT -PDBM 1FSTJTUFOU ,#NBY ,FZDIBJO -PDBM 1FSTJTUFOU  $BDIF%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE 5FNQPSBSZ%JSFDUPSZ -PDBM 5FNQPSBSZ .BZCFQVSHFE
  20. User Interaction

  21. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFX User Interaction Focus

  22. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTBQQBSDIJUFDUVSFGPDVTBOETFMFDUJPO Parallax User Interaction

  23. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHOWJEFP Video User Interaction

  24. Icons and Images

  25. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Icons and Images App Icon.

  26. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFTBQQJDPO Layered Images. Icons and Images

  27. Layered Images. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Icons and Images

  28. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Top Shelf Images. Icons and Images

  29. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Top Shelf Images. Icons and Images

  30. Layout

  31. Layout Y Y ,

  32. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

  33. IUUQTTVQQPSUBQQMFDPNKBKQ)5 Layout

  34. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

  35. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

  36. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHOMBZPVU Layout

  37. Interface Elements

  38. Tab Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  39. TableView Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  40. CollectionView Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  41. Split Views Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  42. Text Fields Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  43. Keyboards Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  44. Search Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  45. Button Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  46. Navigation Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  47. Navigation Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  48. Page Controls Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  49. Activity Indicators Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  50. Alerts Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

  51. Gesture

  52. Gesture

  53. Gesture • Swipe • Touch • Select

  54. Gesture UITapGestureRecognizer • upArrow • downArrow • leftArrow • rightArrow

    • select • menu • playPause
  55. Gesture UITapGestureRecognizer let gesture = UITapGestureRecognizer(target: self, action: #selector(menuButtonPressed(_:))) gesture.allowedPressTypes

    = [NSNumber(value: UIPressType.menu.rawValue)] view.addGestureRecognizer(gesture)
  56. Gesture UITapGestureRecognizer let gesture = UITapGestureRecognizer(target: self, action: #selector(menuButtonPressed(_:))) gesture.allowedPressTypes

    = [NSNumber(value: UIPressType.menu.rawValue)] view.addGestureRecognizer(gesture)
  57. Gesture UISwipeGestureRecognizer • right • left • up • down

  58. Gesture let gesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeUp(_:))) gesture.direction =

    .up view.addGestureRecognizer(gesture) UISwipeGestureRecognizer
  59. Gesture let gesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeUp(_:))) gesture.direction =

    .up view.addGestureRecognizer(gesture) UISwipeGestureRecognizer
  60. Focus

  61. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFX Focus

  62. Focus Focusͷ͍ͭߋ৽͞ΕΔͷ ʁ

  63. Focus • γεςϜ͕ߋ৽Λཁٻͨ͠ͱ͖ • Ϣʔβʔͷૢ࡞ • ΞϓϦέʔγϣϯ͕ߋ৽Λཁٻͨ͠ͱ͖

  64. Focus Focus͸୭͕ߋ৽͢Δͷ ʁ

  65. Focus IUUQTEFWFMPQFSBQQMFDPNMJCSBSZDPOUFOUEPDVNFOUBUJPO(FOFSBM$PODFQUVBM"QQMF57@1( 8PSLJOHXJUIUIF"QQMF573FNPUFIUNM Focus Engine

  66. Focus Focus Engine͕ݕࡧ͢Δൣғ͸ɺݱࡏFocus͞Ε͍ͯ ΔViewͷେ͖͞ʹԠܾͯ͡·ΓɺͦͷViewΛى఺ͱ ͯ͠ɺಈ͖ͷํ޲ʹ͋ΔFocusՄೳͳྖҬΛݟ͚ͭͯ ߋ৽ Focus Engine

  67. Focus Focus Engine͸ɺView֊૚ͷFocusಈ࡞Λఆٛ͢Δ UIFocusEnvironmentϓϩτίϧʹैͬͯFocusΛ੍ ޚ Focus Engine

  68. Focus IUUQTEFWTUSFBNJOHDEOBQQMFDPNWJEFPTXXEDTOWXLF@GPDVT@JOUFSBDUJPO@JO@UWPT@QEG UIFocusEnvironment

  69. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  70. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  71. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  72. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  73. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  74. Focus IUUQTEFWTUSFBNJOHDEOBQQMFDPNWJEFPTXXEDTOWXLF@GPDVT@JOUFSBDUJPO@JO@UWPT@QEG UIFocusEnvironment

  75. Focus public var preferredFocusEnvironments: [UIFocusEnvironment] { get } public func

    shouldUpdateFocus(in context: UIFocusUpdateContext) -> Bool public func setNeedsFocusUpdate() public func updateFocusIfNeeded() public func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 11.0, *) optional public func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? UIFocusEnvironmentϓϩτίϧ
  76. Focus UIFocusEnvironmentʹ४ڌ͍ͯ͠ΔΫϥε

  77. Focus • UIView • UIViewController • UIPresentationController

  78. Focus @available(tvOS 10.0, *) public protocol UIFocusItem : UIFocusEnvironment {

    public var canBecomeFocused: Bool { get } } UIFocusItemϓϩτίϧ
  79. Focus FocusՄೳͳUIKitͷΫϥε

  80. Focus • UIButton • UITextField • UITableView • UICollectionView •

    UITextView • UISegmentedControl • UISearchBar • etc..
  81. Focus IUUQTEFWTUSFBNJOHDEOBQQMFDPNWJEFPTXXEDTOWXLF@GPDVT@JOUFSBDUJPO@JO@UWPT@QEG

  82. Focus UILabelͳͲσϑΥϧτͰϑΥʔΧε͞Εͳ͍ViewΛ ϑΥʔΧεͤ͞Δʹ͸ ʁ

  83. Focus class CustomLabel: UILabel { override init(frame: CGRect) { super.init(frame:

    frame) isUserInteractionEnabled = true } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) isUserInteractionEnabled = true } override var canBecomeFocused: Bool { return true } } } } UILabel for Focus
  84. Focus override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

    super.didUpdateFocus(in: context, with: coordinator) // Focus if context.nextFocusedView == self { coordinator.addCoordinatedFocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform(scaleX: 1.4, y: 1.4) }, completion: nil) } // UnFocus if context.previouslyFocusedView == self { coordinator.addCoordinatedUnfocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform.identity }, completion: nil) } } UILabel for Focus
  85. Focus override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

    super.didUpdateFocus(in: context, with: coordinator) // Focus if context.nextFocusedView == self { coordinator.addCoordinatedFocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform(scaleX: 1.4, y: 1.4) }, completion: nil) } // UnFocus if context.previouslyFocusedView == self { coordinator.addCoordinatedUnfocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform.identity }, completion: nil) } } UILabel for Focus
  86. Focus override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

    super.didUpdateFocus(in: context, with: coordinator) // Focus if context.nextFocusedView == self { coordinator.addCoordinatedFocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform(scaleX: 1.4, y: 1.4) }, completion: nil) } // UnFocus if context.previouslyFocusedView == self { coordinator.addCoordinatedUnfocusingAnimations({ [weak self] context in self?.transform = CGAffineTransform.identity }, completion: nil) } } UILabel for Focus
  87. Focus UILabel for Focus

  88. Focus UITableView, UICollectionViewͷFocus͸ ʁ

  89. Focus Focus༻ͷdelegate͕tvOS༻ʹ͋Γ·͢

  90. Focus UITableViewDelegate for Focus @available(tvOS 9.0, *) optional public func

    tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool @available(tvOS 9.0, *) optional public func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool @available(tvOS 9.0, *) optional public func tableView(_ tableView: UITableView, didUpdateFocusIn context: UITableViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 9.0, *) optional public func indexPathForPreferredFocusedView(in tableView: UITableView) -> IndexPath?
  91. Focus @available(tvOS 9.0, *) optional public func collectionView(_ collectionView: UICollectionView,

    canFocusItemAt indexPath: IndexPath) -> Bool @available(tvOS 9.0, *) optional public func collectionView(_ collectionView: UICollectionView, shouldUpdateFocusIn context: UICollectionViewFocusUpdateContext) -> Bool @available(tvOS 9.0, *) optional public func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) @available(tvOS 9.0, *) optional public func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? @available(tvOS 9.0, *) optional public func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath @available(tvOS 9.0, *) optional public func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint UICollectionViewDelegate for Focus
  92. Focus @available(tvOS 9.0, *) open var remembersLastFocusedIndexPath: Bool UITableView, UICollectionView

    for Focus
  93. Focus UIImageViewͷFocus͸ʁ

  94. Focus @available(tvOS 9.0, *) open var adjustsImageWhenAncestorFocused: Bool @available(tvOS 9.0,

    *) open var focusedFrameGuide: UILayoutGuide { get } @available(tvOS 11.0, *) open var overlayContentView: UIView { get } @available(tvOS 11.0, *) open var masksFocusEffectToContents: Bool UIImageView for Focus
  95. Focus @available(tvOS 9.0, *) open var adjustsImageWhenAncestorFocused: Bool @available(tvOS 9.0,

    *) open var focusedFrameGuide: UILayoutGuide { get } @available(tvOS 11.0, *) open var overlayContentView: UIView { get } @available(tvOS 11.0, *) open var masksFocusEffectToContents: Bool UIImageView for Focus
  96. Focus imageView.adjustsImageWhenAncestorFocused = true UIImageView for Focus IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFXGPDVTBOEQBSBMMBY

  97. Focus UIImageView for Focus @available(tvOS 9.0, *) open var adjustsImageWhenAncestorFocused:

    Bool @available(tvOS 9.0, *) open var focusedFrameGuide: UILayoutGuide { get } @available(tvOS 11.0, *) open var overlayContentView: UIView { get } @available(tvOS 11.0, *) open var masksFocusEffectToContents: Bool
  98. Focus UIImageView for Focus

  99. Focus let overlayView = UIView(frame: imageView.frame) overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5) imageView.overlayContentView.addSubview(overlayView)

    UIImageView for Focus
  100. Focus let overlayView = UIView(frame: imageView.frame) overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5) imageView.overlayContentView.addSubview(overlayView)

    UIImageView for Focus
  101. Focus // UICollectionView delegate func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context:

    UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { // Focus if let cell = context.nextFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedFocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 0 }, completion: nil) } // UnFocus if let cell = context.previouslyFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedUnfocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 1 }, completion: nil) } } UIImageView for Focus
  102. Focus // UICollectionView delegate func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context:

    UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { // Focus if let cell = context.nextFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedFocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 0 }, completion: nil) } // UnFocus if let cell = context.previouslyFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedUnfocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 1 }, completion: nil) } } UIImageView for Focus
  103. Focus // UICollectionView delegate func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context:

    UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { // Focus if let cell = context.nextFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedFocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 0 }, completion: nil) } // UnFocus if let cell = context.previouslyFocusedView as? CostomCollectionViewCell { coordinator.addCoordinatedUnfocusingAnimations({ context in cell.imageView.overlayContentView.alpha = 1 }, completion: nil) } } UIImageView for Focus
  104. Focus UIImageView for Focus

  105. Focus Focus Update Notification

  106. Focus Focus Update Notification extension NSNotification.Name { @available(tvOS 11.0, *)

    public static let UIFocusDidUpdate: NSNotification.Name @available(tvOS 11.0, *) public static let UIFocusMovementDidFail: NSNotification.Name } @available(tvOS 11.0, *) public let UIFocusUpdateContextKey: String @available(tvOS 11.0, *) public let UIFocusUpdateAnimationCoordinatorKey: String
  107. Focus Focus Update Notification extension NSNotification.Name { @available(tvOS 11.0, *)

    public static let UIFocusDidUpdate: NSNotification.Name @available(tvOS 11.0, *) public static let UIFocusMovementDidFail: NSNotification.Name } @available(tvOS 11.0, *) public let UIFocusUpdateContextKey: String @available(tvOS 11.0, *) public let UIFocusUpdateAnimationCoordinatorKey: String
  108. Focus Focus Update Notification extension NSNotification.Name { @available(tvOS 11.0, *)

    public static let UIFocusDidUpdate: NSNotification.Name @available(tvOS 11.0, *) public static let UIFocusMovementDidFail: NSNotification.Name } @available(tvOS 11.0, *) public let UIFocusUpdateContextKey: String @available(tvOS 11.0, *) public let UIFocusUpdateAnimationCoordinatorKey: String
  109. Focus UIFocusGuideʁ

  110. Focus @available(tvOS 9.0, *) open class UIFocusGuide : UILayoutGuide {

    open var isEnabled: Bool @available(tvOS 10.0, *) open var preferredFocusEnvironments: [UIFocusEnvironment]! } UIFocusGuide
  111. Focus UIFocusGuide

  112. Focus UIFocusGuide

  113. Focus UIFocusGuide

  114. Focus UIFocusGuide

  115. Focus UIFocusGuide

  116. Focus UIFocusGuide 'PDVT(VJEF

  117. Focus UIFocusGuide 'PDVT(VJEF QSFGFSSFE'PDVT&OWJSPONFOUT

  118. Focus UIFocusGuide

  119. Focus focusGuide = UIFocusGuide() view.addLayoutGuide(focusGuide) // Anchor the top left

    of the focus guide. focusGuide.topAnchor.constraint(equalTo: button.topAnchor).isActive = true focusGuide.leftAnchor.constraint(equalTo: collectionView.leftAnchor).isActive = true // Anchor the width and height of the focus guide. focusGuide.heightAnchor.constraint(equalTo: button.heightAnchor).isActive = true focusGuide.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true focusGuide.preferredFocusEnvironments = [button] UIFocusGuide
  120. Focus focusGuide = UIFocusGuide() view.addLayoutGuide(focusGuide) // Anchor the top left

    of the focus guide. focusGuide.topAnchor.constraint(equalTo: button.topAnchor).isActive = true focusGuide.leftAnchor.constraint(equalTo: collectionView.leftAnchor).isActive = true // Anchor the width and height of the focus guide. focusGuide.heightAnchor.constraint(equalTo: button.heightAnchor).isActive = true focusGuide.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true focusGuide.preferredFocusEnvironments = [button] UIFocusGuide
  121. Focus focusGuide = UIFocusGuide() view.addLayoutGuide(focusGuide) // Anchor the top left

    of the focus guide. focusGuide.topAnchor.constraint(equalTo: button.topAnchor).isActive = true focusGuide.leftAnchor.constraint(equalTo: collectionView.leftAnchor).isActive = true // Anchor the width and height of the focus guide. focusGuide.heightAnchor.constraint(equalTo: button.heightAnchor).isActive = true focusGuide.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true focusGuide.preferredFocusEnvironments = [button] UIFocusGuide
  122. Focus focusGuide = UIFocusGuide() view.addLayoutGuide(focusGuide) // Anchor the top left

    of the focus guide. focusGuide.topAnchor.constraint(equalTo: button.topAnchor).isActive = true focusGuide.leftAnchor.constraint(equalTo: collectionView.leftAnchor).isActive = true // Anchor the width and height of the focus guide. focusGuide.heightAnchor.constraint(equalTo: button.heightAnchor).isActive = true focusGuide.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true focusGuide.preferredFocusEnvironments = [button] UIFocusGuide
  123. Focus focusGuide = UIFocusGuide() view.addLayoutGuide(focusGuide) // Anchor the top left

    of the focus guide. focusGuide.topAnchor.constraint(equalTo: button.topAnchor).isActive = true focusGuide.leftAnchor.constraint(equalTo: collectionView.leftAnchor).isActive = true // Anchor the width and height of the focus guide. focusGuide.heightAnchor.constraint(equalTo: button.heightAnchor).isActive = true focusGuide.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true focusGuide.preferredFocusEnvironments = [button] UIFocusGuide
  124. Focus Focus͕͏·͍͔͘ͳ͍৔߹

  125. Focus • canBecomeFocused͕falseʹͳͬͯͳ͍͔ • isHidden͕trueʹͳͬͯͳ͍͔ • alpha͕0Ͱͳ͍͔ • isUserInteractionEnabled͕falseʹͳͬͯͳ͍͔ •

    view͕ӅΕ͍ͯͳ͍͔ Focus͕͏·͍͔͘ͳ͍৔߹
  126. Focus Focusͷdebug

  127. Focus Focus Update Logging

  128. Focus The result of the focus update was determined from

    the following preferred focus search: | | Starting preferred focus search: | |--> Searching <UIFocusSystem 0x60000028dc00>... | |--> Searching <UIScreen 0x6080001d3fb0>... | |--> Searching <UIWindow 0x7fb79cb02af0>... | |--> Searching <tvos_sample_for_iosdc.RootViewController 0x7fb79c904da0>... | |--> Searching <UIView Focus Update Logging
  129. Focus po UIFocusDebugger.status() <UIButton 0x7f97bac05b90> is currently focused. UIFocusDebugger

  130. Focus po UIFocusDebugger.simulateFocusUpdateRequest(from: imageView) Simulating a fake focus update request

    from <UIImageView 0x7ff3ce2106d0>... (<tvos_sample_for_iosdc.MainCollectionViewCell 0x7ff3ce20fe60> is currently focused) The following issues were found that would normally prevent this environment's request from being accepted by the focus system (these will be ignored for the purposes of this test): - ISSUE: This environment does not contain the currently focused item. Starting preferred focus search: |--> Searching <UIImageView 0x7ff3ce2106d0>... No more preferences for this environment, and there are no focusable items in this environment to prefer by default. This environment does not prefer a valid focusable item, nor any other environments. Simulated Result: Successfully updated focus to nil. UIFocusDebugger
  131. Focus po UIFocusDebugger.checkFocusability(for: label) The following issues were found that

    would prevent this item from being focusable: - ISSUE: This view has isUserInteractionEnabled set to NO. Views must allow user interaction to be focusable. UIFocusDebugger
  132. Conclusion

  133. Conclusion • iOSͱͷҧ͍͸Focus • ඪ४ͷUI/UXʹ४ڌ͠Α͏ • tvOSରԠ͸೉͘͠ͳ͍

  134. Thank you ࢀߟࢿྉ https://developer.apple.com/tvos/resources/ https://developer.apple.com/videos/play/wwdc2017/209/ https://developer.apple.com/videos/play/wwdc2017/224/