1
Help us understand the problem. What are the problem?

posted at

Android API29未満で getRawX(index)をする(回転、拡大、縮小に対応)

getX()とgetRawX()

MotionEventにはgetX()とgetRawX()という異なるメソッドがあります。
(もちろん同様にy座標に関するメソッドもあります)

この2つのメソッドの違いは、getX()はEventの対象となるViewのローカル座標、getRawX()はスクリーン上の座標を取得するという点になります。

getRawX()とgetRawX(index)

API29からgetRaw(index)というメソッドが追加されました。
MotionEventではタッチされている座標(pointer)が複数ある場合があり、indexを指定することでpointerごとの座標を取得することができます。

しかし、getRawX(index)はAPI29から追加されたメソッドのため、API29未満では自分で計算を行うことになります。
API29未満にもgetX(index)というメソッドがあります、これは指定したindexのpointerのローカル座標を取得するメソッドです。このメソッドを利用して計算をします。

ローカル座標からスクリーン座標への変換

具体的なコードは以下になります。
Viewが回転、拡大、縮小していた場合にも正しい座標が取得できるようになっています。
回転、拡大、縮小が不要な場合には該当のコードを削除してください。

private fun getRawPoint(view: View, event: MotionEvent, index: Int): PointF {
    val location = intArrayOf(0, 0)
    view.getLocationOnScreen(location)
    var x = event.getX(index) * view.scaleX
    var y = event.getY(index) * view.scaleY
    var angle = Math.toDegrees(atan2(y.toDouble(), x.toDouble()))
    angle += view.rotation.toDouble()
    val length = hypot(x, y)
    x = (length * cos(Math.toRadians(angle))).toFloat() + location[0]
    y = (length * sin(Math.toRadians(angle))).toFloat() + location[1]
    return PointF(x, y)
}

scaleが変更されていた場合を考慮し、x, yの値にscaleをかけています。
また、回転していた場合を考慮し、アークタンジェントを求めるatan2(y, x)を利用して座標から角度を求めrotationと合計しています。
解説のため下図を用意しました。
rotationでαの角度、atan2(y, x)でβの角度を求めています。
lengthが三角関数の斜辺となりα + βが三角関数のθとなるのであとはsin、cosで座標が求められますね。

スクリーンショット 2021-03-08 10.35.06.png

API29未満でMotionEventからスクリーン座標を取得したいときにお使いください。

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
1
Help us understand the problem. What are the problem?