LoginSignup
3
3

More than 3 years have passed since last update.

watchOSで〇〇アニメーション

Last updated at Posted at 2020-02-07

watchOSアプリを開発した際に、いくつかアニメーションをつくりました
その中でうまくいったこと😹いかなかったこと😹があるので、そのまとめになります

基本のローディングアニメーション

実装方法は以下の2つ

  1. パラパラ画像をつかう
  2. APNGをつかう

パラパラ画像をつかう

Appleのサンプルコード的にも正攻法といって良いでしょう
特徴としては、

  • Asset Catalogを利用できるため、解像度の対応がしやすい
  • 画像枚数が増えると管理が手間(あくまでAPNGにくらべて)

です

シンプルな Duration 指定の場合


// animatedImage: WKInterfaceImage
animatedImage.setImage(UIImage(named: "Bus"))
animatedImage.startAnimating()

startAnimatingはStoryboard上で設定されたDurationでアニメーションを行います

Storyboard
スクリーンショット 2020-02-07 17.18.45.png

Asset Catalog
スクリーンショット 2020-02-07 17.21.39.png

Duration + Repeat Count 指定の場合

animatedImage.setImage(UIImage(named: "Bus"))    
animatedImage.startAnimatingWithImages(in: NSMakeRange(0, 4), duration: 2.0, repeatCount: 3)

APNGをつかう

APNGはアニメーションするPNG画像のことです。

特徴としては、

  • リソースが1つになるので、画像パラパラよりも管理が楽
  • 画像は、Extension ターゲットのリソースに入れる
  • APNGの尺に合わせたDurationにすれば良い
  • watchOSはAPNG対応のライブラリがない(*注)ので自前でソースコードを書く必要がある

*注:下書き時点ではなかったのですが、今ならSDWebImage/SDWebImageSwiftUIが使えるかもしれません:tada:

実装例については、Apple Watch で GIF/APNG を使う (ライブラリ不使用) が参考になりました(ありがとうございました)
こちらでスムーズにアニメーションができました

カウントダウンで遷移アニメーション😹

やりたかったのは「3 -> 2 -> 1 -> 画面遷移」でした
前述の「パラパラ画像もしくはAPNGをつかい、画面側でタイマーセットをし一定時間後に画面遷移する」という実装を行いましたが、カウントダウンし切る前に遷移してしまったり・・・とうまくいきませんでした

(こちらについて、シンプルで良い方法があればご教授いただけるとうれしいです😹)

より動的なアニメーション

たとえば位置情報に基づいてアニメーションを移動・変更したい等のケースでは、Sprite Kit を使うことになると思います
ただし、watchOSで複雑なアニメーションをする際には、パフォーマンスに気を配るとよさそうです
特にApple Watch Series 1などでは、最悪の場合、いつの間にかアプリがパージされます😹

やるといいこと

スレッド管理

断然 ReactiveX/RxSwift の利用が楽です

  • アニメーションの移動についての計算はバックグラウンド処理
  • 描画処理はメインスレッドで実行

という実装にしましょう

SKTextureAtlas の利用

公式ドキュメントは About Texture Atlases
SKTextureAtlasの利用により、メモリ使用量、描画パフォーマンスが向上するようです

まず、使用するテクスチャについては、Asset Catalog > + > New Sprite Atlas で専用フォルダをつくり、格納しましょう

Asset Catalog
スクリーンショット 2020-02-07 18.32.54.png

テクスチャアトラスからテクスチャを作成

static let TextureAtlasName = "Sprite Atlasのフォルダ名"

static let TextureAtlas = SKTextureAtlas(named: TextureAtlasName)

lazy var textures: [SKTexture] = {
    var textures = [SKTexture]()
    let numberOfTextures = TextureAtlas.textureNames.count - 1
    for index in 0...numberOfTextures {
        let name = String(format: "%@%d", TextureAtlasName, index)
        textures.append(TextureAtlas.textureNamed(name))
    }
    return textures
}()

テクスチャの切替のみ(要はパラパラ)でアニメーションする場合は以下のような実装

func animate() {
    let node = SKSpriteNode(..省略..) // アニメーション大賞のSKSpriteNodeオブジェクト生成
    let action = SKAction.animate(with: textures, timePerFrame: 0.03)
    let repeatAction = SKAction.repeatForever(action)

    node.run(repeatAction, withKey: key) // node: SKSpriteNode
}

画像比率の適用

Sprite Kitを使う際にはAutoLayoutやCore Graphicsのような簡単な配置ができません
そのため、全端末でうつくしく表示するためには、画像比率に対してテクスチャサイズの変更等が必要かもしれません

たとえば、背景画像を画面いっぱいに表示したい場合は以下のように SKScene のサイズを指定します

InterfaceController.swift
func setupScene() {
    let image: UIImage = BackgroundImage
    let size = contentFrame.size
    let portraitRatio = size.height / image.size.width
    let landscapeRatio = size.width / image.size.height
    let multiplier = min(portraitRatio, landscapeRatio)
    let sceneSize = CGSize(
        width: image.size.width * multiplier,
        height: image.size.height * multiplier)
    let scene = SKScene(size: sceneSize)
    scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    scene.scaleMode = .aspectFit
    sceneInterface.presentScene(scene)
}

以降、このScene上で配置するNodeのサイズは、multiplierを使った計算が必要になるでしょう

まとめ

watchOS6よりWatch-only appの開発が可能になりました。
まだアプリ数は少ないようですが、AppleWatch用のApp Storeもリリースされました。
これからwatchOSアプリ市場が盛り上がることを期待!

以上です🎉🎉🎉
ありがとうございました😽

Thanks to

SpriteKit Animations and Texture Atlases in Swift
Apple Watch で GIF/APNG を使う (ライブラリ不使用)
WatchKit のカスタムUI実現方法のまとめ

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3