Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

What's New in tvOS11 まとめ

※ まだ正式リリースされていない情報なので変更の可能性があります⚠️

今回KeynoteではAmazon Prime Videoの話しかされなかったtvOSですが、API Referenceを見るとそれなりに変更があったのでWhat's New in tvOSをまとめてみました👏 ※iOSと被っているところは省いています🙇

Focus Update Notifications

  • Focusに対して更新処理が走る時に通知を受け取れるようになった
  • Focusの移動に失敗した場合の通知も追加されている
static let UIFocusDidUpdate: NSNotification.Name

static let UIFocusMovementDidFail: NSNotification.Name

Protocol Extensions

UIFocusItemプロトコルが拡張されて、自身が今Focusされているか確認できます。

var isFocused: Bool { get }

UIFocusEnvironmentプロトコルが拡張されて、自身が他のFocusEnvirionmentに含まれているか確認できます。

func contains(_ environment: UIFocusEnvironment) -> Bool

Focus Animations

Focusの移動時にアニメーションを定義できます。

// for focusing item
func addCoordinatedFocusingAnimations(_ animations: ((UIFocusAnimationContext) -> Void)?,
                           completion: (() -> Void)? = nil)

// for unfocusing item
func addCoordinatedUnfocusingAnimations(_ animations: ((UIFocusAnimationContext) -> Void)?,
                             completion: (() -> Void)? = nil)

Runs the specified set of animations together with the system animations for adding focus to an item.

今まで下記のようにやっていた処理はひとつのaddCoordinatedAnimations:completionの中にフォーカス時とアンフォーカス時のアニメーションが入っていたので滑らかなアニメーションができませんでした😭

func collectionView(
  _ collectionView: UICollectionView,
  didUpdateFocusIn context: UICollectionViewFocusUpdateContext,
  with coordinator: UIFocusAnimationCoordinator) {

  coordinator.addCoordinatedAnimations({
    if let indexPath = context.nextFocusedIndexPath {

      let cell = collectionView.cellForItem(at: indexPath) as? NewCell
      cell?.imageView.transform = CGAffineTransform(rotationAngle: 90.0)
    }

    if let indexPath = context.previouslyFocusedIndexPath {

      let cell = collectionView.cellForItem(at: indexPath) as? NewCell
      cell?.imageView.transform = .identity
    }
  })
}

今回はフォーカス時とアンフォーカス時のアニメーションブロックが別で定義されている為、それぞれのアニメーションが滑らかに動きます。また、Focusの移動スピードに合わせてアニメーションの早さも調節されます👏(シミュレーターのcmd+tで見てみるとわかりやすいです)

  if let indexPath = context.nextFocusedIndexPath {

    let cell = collectionView.cellForItem(at: indexPath) as? NewCell
    coordinator.addCoordinatedFocusingAnimations({ animationContext in

      cell?.imageView.transform = CGAffineTransform(rotationAngle: 90.0)

    })
  }

  if let indexPath = context.previouslyFocusedIndexPath {

    let cell = collectionView.cellForItem(at: indexPath) as? NewCell
    coordinator.addCoordinatedUnfocusingAnimations({ animationContext in

      cell?.imageView.transform = .identity

    })
  }

Custom Focus Sounds

  • フォーカス移動時に流れる音をカスタマイズできるようになった
  • UIFocusSystemというクラスが追加されたことによって可能になった

UIFocusSystem

現在のユーザーインタフェース上にあるフォーカスの状態を管理するクラス。
今まではupdateFocusIfNeededのように自身のフォーカスの更新しかできませんでしたが、このクラスは全てのフォーカスの更新ができます。

func requestFocusUpdate(to environment: UIFocusEnvironment)

func updateFocusIfNeeded()

また、現在フォーカスされているオブジェクトやどのFocusEnvirionmentに含まれているかもチェックもできます。

weak var focusedItem: UIFocusItem? { get }

class func environment(_ environment: UIFocusEnvironment,
              contains otherEnvironment: UIFocusEnvironment) -> Bool

その中にひとつだけフォーカス時の音を変更するメソッドがあります。
ローカルのサウンドファイルのURLと識別子を指定するだけでアプリ内にグローバルに反映されます。ただし、サウンドファイルは30秒未満でなくてはいけません。

class func register(_ soundFileURL: URL,
 forSoundIdentifier identifier: UIFocusSoundIdentifier)
let url = Bundle.main.url(forResource: "a", withExtension: "m4a")!
let identifier = UIFocusSoundIdentifier(rawValue: "newSounds")
UIFocusSystem.register(url, forSoundIdentifier: identifier)

下記のようなサウンドの調整も行われるようです。

  • スピードに合わせて音量が変更される
  • フォーカスの移動方向(左右)によっても異なる

また、オブジェクトがフォーカスを更新するタイミングでカスタムとデフォルトとなしの切り替えもできます。例えばサイズの異なるオブジェクトになる場合は音を変えるというのは良いプラクティスだそうです👌

// UIFocusEnvironment Protocol
optional func soundIdentifierForFocusUpdate(in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier?
override func soundIdentifierForFocusUpdate(
  in context: UIFocusUpdateContext) -> UIFocusSoundIdentifier? {

  return identifier
}

Support for SceneKit

SceneKitとSpriteKitでもフォーカスを扱えるようになった
UIFocusItemの継承クラスにSKNodeSCNodeが追加されている。

Focus Update Logging

-UIFocusUpdateLoggingEnabled=YESの設定をXcode上で行うとフォーカスに関するログを吐く。素晴らしい。

The result of the focus update was determined from the following preferred focus search:
|
|   Starting preferred focus search:
|   |--> Searching <UIFocusSystem 0x60800008c1c0>...
|        |--> Searching <UIScreen 0x6000001c2850>...
|             |--> Searching <UIWindow 0x7fb5d1401c90>...

UIFocusDebugger

フォーカスをデバッグするためのクラスが追加されました。
po UIFocusDebugger.foo()でFocusの状態を見たり検証したりできます。

  • status(): フォーカスされているオブジェクトに関する情報
  • simulateFocusUpdateRequest(from: _): 特定のFocusEnvirionmentからフォーカスの更新を試せる
  • checkFocusability(for: _): Focusできるかチェックできる(できない場合は理由も分かる)
  • help(): 使用できるコマンド(メソッド)全部出してくれる
(lldb) po UIFocusDebugger.status()
<TVOSample.SomeCell 0x7f80f5508340> is currently focused.

結構やりたかったことや実装が面倒だった部分が解消されている気がします。何より捉えにくいフォーカスをデバッグしやすくなったのは嬉しい🎉
サンプルコードもあげました。

おしまい👏

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?