Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

About me Yuji Hato CyberAgent, Inc. / AbemaTV, Inc. dekatotoro @dekatotoro Contributed services

Slide 3

Slide 3 text

Apple TV

Slide 4

Slide 4 text

Apple TV

Slide 5

Slide 5 text

・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

Slide 6

Slide 6 text

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円

Slide 7

Slide 7 text

Remote

Slide 8

Slide 8 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

Slide 9

Slide 9 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

Slide 10

Slide 10 text

Swipe Click Tap IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTSFNPUFBOEDPOUSPMMFST Remote

Slide 11

Slide 11 text

Development Method

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Limited App Size

Slide 14

Slide 14 text

Limited App Size 200MB 4GB

Slide 15

Slide 15 text

Data Storage

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

User Interaction

Slide 21

Slide 21 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFX User Interaction Focus

Slide 22

Slide 22 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTBQQBSDIJUFDUVSFGPDVTBOETFMFDUJPO Parallax User Interaction

Slide 23

Slide 23 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHOWJEFP Video User Interaction

Slide 24

Slide 24 text

Icons and Images

Slide 25

Slide 25 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Icons and Images App Icon.

Slide 26

Slide 26 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFTBQQJDPO Layered Images. Icons and Images

Slide 27

Slide 27 text

Layered Images. IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Icons and Images

Slide 28

Slide 28 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Top Shelf Images. Icons and Images

Slide 29

Slide 29 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJDPOTBOEJNBHFT Top Shelf Images. Icons and Images

Slide 30

Slide 30 text

Layout

Slide 31

Slide 31 text

Layout Y Y ,

Slide 32

Slide 32 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

Slide 33

Slide 33 text

IUUQTTVQQPSUBQQMFDPNKBKQ)5 Layout

Slide 34

Slide 34 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

Slide 35

Slide 35 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHO Layout

Slide 36

Slide 36 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTWJTVBMEFTJHOMBZPVU Layout

Slide 37

Slide 37 text

Interface Elements

Slide 38

Slide 38 text

Tab Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 39

Slide 39 text

TableView Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 40

Slide 40 text

CollectionView Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 41

Slide 41 text

Split Views Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 42

Slide 42 text

Text Fields Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 43

Slide 43 text

Keyboards Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 44

Slide 44 text

Search Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 45

Slide 45 text

Button Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 46

Slide 46 text

Navigation Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 47

Slide 47 text

Navigation Bars Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 48

Slide 48 text

Page Controls Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 49

Slide 49 text

Activity Indicators Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 50

Slide 50 text

Alerts Interface Elements IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTJOUFSGBDFFMFNFOUT

Slide 51

Slide 51 text

Gesture

Slide 52

Slide 52 text

Gesture

Slide 53

Slide 53 text

Gesture • Swipe • Touch • Select

Slide 54

Slide 54 text

Gesture UITapGestureRecognizer • upArrow • downArrow • leftArrow • rightArrow • select • menu • playPause

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Gesture UISwipeGestureRecognizer • right • left • up • down

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Focus

Slide 61

Slide 61 text

IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFX Focus

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

Focus Focus͸୭͕ߋ৽͢Δͷ ʁ

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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ϓϩτίϧ

Slide 70

Slide 70 text

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ϓϩτίϧ

Slide 71

Slide 71 text

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ϓϩτίϧ

Slide 72

Slide 72 text

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ϓϩτίϧ

Slide 73

Slide 73 text

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ϓϩτίϧ

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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ϓϩτίϧ

Slide 76

Slide 76 text

Focus UIFocusEnvironmentʹ४ڌ͍ͯ͠ΔΫϥε

Slide 77

Slide 77 text

Focus • UIView • UIViewController • UIPresentationController

Slide 78

Slide 78 text

Focus @available(tvOS 10.0, *) public protocol UIFocusItem : UIFocusEnvironment { public var canBecomeFocused: Bool { get } } UIFocusItemϓϩτίϧ

Slide 79

Slide 79 text

Focus FocusՄೳͳUIKitͷΫϥε

Slide 80

Slide 80 text

Focus • UIButton • UITextField • UITableView • UICollectionView • UITextView • UISegmentedControl • UISearchBar • etc..

Slide 81

Slide 81 text

Focus IUUQTEFWTUSFBNJOHDEOBQQMFDPNWJEFPTXXEDTOWXLF@GPDVT@JOUFSBDUJPO@JO@UWPT@QEG

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

Focus UILabel for Focus

Slide 88

Slide 88 text

Focus UITableView, UICollectionViewͷFocus͸ ʁ

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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?

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

Focus @available(tvOS 9.0, *) open var remembersLastFocusedIndexPath: Bool UITableView, UICollectionView for Focus

Slide 93

Slide 93 text

Focus UIImageViewͷFocus͸ʁ

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

Focus imageView.adjustsImageWhenAncestorFocused = true UIImageView for Focus IUUQTEFWFMPQFSBQQMFDPNUWPTIVNBOJOUFSGBDFHVJEFMJOFTPWFSWJFXGPDVTBOEQBSBMMBY

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

Focus UIImageView for Focus

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

Focus UIImageView for Focus

Slide 105

Slide 105 text

Focus Focus Update Notification

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

Focus UIFocusGuideʁ

Slide 110

Slide 110 text

Focus @available(tvOS 9.0, *) open class UIFocusGuide : UILayoutGuide { open var isEnabled: Bool @available(tvOS 10.0, *) open var preferredFocusEnvironments: [UIFocusEnvironment]! } UIFocusGuide

Slide 111

Slide 111 text

Focus UIFocusGuide

Slide 112

Slide 112 text

Focus UIFocusGuide

Slide 113

Slide 113 text

Focus UIFocusGuide

Slide 114

Slide 114 text

Focus UIFocusGuide

Slide 115

Slide 115 text

Focus UIFocusGuide

Slide 116

Slide 116 text

Focus UIFocusGuide 'PDVT(VJEF

Slide 117

Slide 117 text

Focus UIFocusGuide 'PDVT(VJEF QSFGFSSFE'PDVT&OWJSPONFOUT

Slide 118

Slide 118 text

Focus UIFocusGuide

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

Focus Focus͕͏·͍͔͘ͳ͍৔߹

Slide 125

Slide 125 text

Focus • canBecomeFocused͕falseʹͳͬͯͳ͍͔ • isHidden͕trueʹͳͬͯͳ͍͔ • alpha͕0Ͱͳ͍͔ • isUserInteractionEnabled͕falseʹͳͬͯͳ͍͔ • view͕ӅΕ͍ͯͳ͍͔ Focus͕͏·͍͔͘ͳ͍৔߹

Slide 126

Slide 126 text

Focus Focusͷdebug

Slide 127

Slide 127 text

Focus Focus Update Logging

Slide 128

Slide 128 text

Focus The result of the focus update was determined from the following preferred focus search: | | Starting preferred focus search: | |--> Searching ... | |--> Searching ... | |--> Searching ... | |--> Searching ... | |--> Searching

Slide 129

Slide 129 text

Focus po UIFocusDebugger.status() is currently focused. UIFocusDebugger

Slide 130

Slide 130 text

Focus po UIFocusDebugger.simulateFocusUpdateRequest(from: imageView) Simulating a fake focus update request from ... ( 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 ... 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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

Conclusion

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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