jarinosuke blog

about software engineering, mostly about iOS

UIMotionEffect の Subclass 化

UIMotionEffect とは

iOS 7 の登場により視差効果などの、デバイスの動作がダイナミックにビューに反映される効果が多用されるようになりました。

iOS 7 登場前にそのようなことをしようとした場合、CoreMotion を用いて加速度センサに自分でアクセスして実装しなければいけなかったりと、かなり面倒な事が多かったように思います。

それを解決するべく登場したのが UIMotionEffect です。

http://img.gawkerassets.com/img/18znnfqf2wrrfgif/ku-xlarge.gif

UIMotionEffect は iOS 7 から提供されている抽象クラスで、UIView に対して実際のユーザがデバイスに対して行う動作を元にした修飾を可能にしてくれます。

UIMotionEffect の基本的な使い方に関しては、以下の記事が参考になると思います。

Motion Effects(iOS 7の「視差効果」の実装方法)

今回は UIMotionEffect を Subclass 化しカスタマイズしたい時の工夫を紹介します。

Subclass 化が必要な場合

いきなりですが UIMotionEffect は抽象クラスなので、そのまま使う事はできません。

そこで Apple は UIInterpolatingMotionEffect という UIMotionEffect を継承した実クラスを提供してくれています。

UIInterpolatingMotionEffect はユーザの動作に対して linear な値を以て修飾を行ってくれるのでほとんどはこれで事足ります。

しかし、場合によっては linear ではなく 2次関数的な修飾を行いたい時があり、そのような場合は Subclass 化を行う事が必要になります。

Subclass 化における工夫、注意点

  • relativeValue の定義 変化の最大・最小値として、 UIInterpolatingMotionEffect では minimumRelativeValue と maximumRelativeValue が定義されています。 しかし上記の値は NSNumber で定義されています。 細かいですが個人的には CGFloat で充分事足りるのでは、と思いました。

  • viewerOffset の意味 UIMotionEffect を継承するうえで、実装する上で力を入れるのは以下のメソッドだけです。

- (NSDictionary *)keyPathsAndRelativeValuesForViewerOffset:(UIOffset)viewerOffset {
 }

これはユーザがデバイスに対して動作を行う度に呼ばれ、その時の viewerOffset が呼ばれるのですが、この viewerOffset がとてもとっつきにくいです。

CoreMotion の x,y,z 軸が頭にあるので、iPhone を地面に対して水平や平行にして viewerOffset の中身を覗いてみても微妙にズレています。

viwerOffset、実は一般的に人間が iPhone を見る角度からの horizontal と vertical のズレを表現しているんですね。なのでイメージとしては地球の地軸みたいな感じで、iPhone を画面側が目に見えるように手を取り、地面に対してちょっと斜めにすると、horizontal と vertical が 0 に近づきます。

参考

Introduction to UIMotionEffect