カスタムビューをインタラクティブにする

Compose を試す
Jetpack Compose は、Android に推奨される UI ツールキットです。Compose でレイアウトを操作する方法を学習します。
<ph type="x-smartling-placeholder"></ph> ジェスチャー →

UI の描画は、カスタムビューを作成するプロセスの一部にすぎません。さらに、 ユーザーの入力によく似た方法でビューを 実世界の行動を再現できます。

アプリ内のオブジェクトを実際のオブジェクトのように動作させます。たとえば、 アプリの画像が存在しなくなり、別の場所に再表示されます。これは、オブジェクトの やってはいけません代わりに、画像を 1 か所から 別のものです。

ユーザーはインターフェースの微妙な行動や感覚にも反応し、 繊細さが求められる要素です。たとえば、ユーザーが UI オブジェクトをフリングすると、 動きを遅らせる最初に、ユーザーに慣性を持たせます。最後 物体の動きが 物体の向こう側に フリング。

このページでは、Android フレームワークの機能を使用して、 カスタムビューに追加できます。

その他の関連情報については、 入力イベントの概要 プロパティ アニメーション 概要をご覧ください。

入力操作を処理する

他の多くの UI フレームワークと同様に、Android は入力イベントモデルをサポートしています。ユーザー アクションを、コールバックをトリガーするイベントに変換できます。また、 コールバックを使用して、アプリがユーザーにどのように応答するかをカスタマイズできます。最も一般的な入力は Android システムの「touch」イベントは onTouchEvent(android.view.MotionEvent)。 次のように、このメソッドをオーバーライドしてイベントを処理します。

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

Java

@Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

タッチイベント自体は特に有用ではありません。最新のタッチ UI タップ、プル、押し、 フリング、ズームなどです未加工のタッチイベントをジェスチャーに変換するには、 提供 GestureDetector

クラスのインスタンスを渡して GestureDetector を作成します。 実装する GestureDetector.OnGestureListener。 少数のジェスチャーのみを処理したい場合は、 GestureDetector.SimpleOnGestureListener GestureDetector.OnGestureListener を実装する代わりに、 行うことができます。たとえば、次のコードは、この変数を拡張するクラスを GestureDetector.SimpleOnGestureListener とオーバーライド onDown(MotionEvent)

Kotlin

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

Java

class MyListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
detector = new GestureDetector(getContext(), new MyListener());

GestureDetector.SimpleOnGestureListener を使用するかどうか、 常に onDown() true を返すメソッドです。この操作が必要なのは、 onDown() メッセージで始まります。false を返す場合 onDown() から、 GestureDetector.SimpleOnGestureListener に追加すると、システムは 残りのジェスチャーは無視してかまいません。 GestureDetector.OnGestureListener は呼び出されません。返却のみ 全体を無視する場合は、onDown()false 行います。

GestureDetector.OnGestureListener を実装して GestureDetector のインスタンスの場合は、 GestureDetector: 受信したタッチイベントを解釈します onTouchEvent()

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

Java

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = detector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

タップイベントを onTouchEvent() に渡すと、 操作の一部として認識した場合、false を返します。その後、 独自のジェスチャー検出コードを作成できます。

身体的にもっともらしい動きを作成する

ジェスチャーはタッチスクリーン デバイスを操作するための便利な手段ですが、 直感に反するもので 物理的に 提示します

たとえば、水平方向のフリング ジェスチャーを ビューに描画されたアイテムを垂直軸で回転するように設定します。この操作 UI がフリングの方向にすばやく動くことで応答する場合に意味がありますが、 ユーザーがフライホイールを押して回転させたかのように、速度が低下します。

使用方法については、 スクロールをアニメーション化する 操作: 独自のスコールの実装方法が詳しく説明されています。 確認します。しかし、フライホイールの感覚をシミュレートするのは簡単なことではありません。物理学はたくさん フライホイールモデルを正しく機能させるには 数学が必要です幸い Android には、このような動作をシミュレートするヘルパークラスが用意されています。「 Scroller クラスが、フライホイール スタイルのフリング ジェスチャーを処理する基盤となります。

フリングを開始するには、以下を呼び出します。 fling() 開始速度、xy の最小値と最大値を使って計算される 値を返します。速度の値は、 GestureDetector

Kotlin

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

Java

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
    return true;
}
<ph type="x-smartling-placeholder">

fling() を呼び出すと、フリングの物理モデルが設定されます。 行います。その後、以下を呼び出して Scroller を更新します。 Scroller.computeScrollOffset() 定期的に更新することもできます。computeScrollOffset() が次を更新します。 Scroller オブジェクトの内部状態を、現在の時刻と その位置における x 位置と y 位置を物理モデルを使って計算する あります。発信 getCurrX() および getCurrY() これらの値を取得できます。

ほとんどのビューは、Scroller オブジェクトの xy を渡します。 直接接続できる scrollTo()。 これとは異なり、このサンプルでは現在のスクロール位置の x を使用しています。 ビューの回転角度を設定します

Kotlin

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

Java

if (!scroller.isFinished()) {
    scroller.computeScrollOffset();
    setItemRotation(scroller.getCurrX());
}

Scroller クラスはスクロール位置を計算しますが、 自動的にその位置がビューに適用されることはありません。新しい座標を適用 スクロール アニメーションが滑らかに見えるようにします。この 2 つの方法で、 手順:

  • 呼び出して強制的に再描画を行う postInvalidate() fling() の呼び出し後。この方法を使用するには、 スクロール オフセットを計算 onDraw() スクロール オフセットが発生するたびに postInvalidate() を呼び出す できます。
  • セットアップする ValueAnimator フリングの継続時間中をアニメーション化し、 更新するには、関数を呼び出して addUpdateListener()。 この手法を使用すると、 View

移行をスムーズにする

ユーザーは、最新の UI が状態間をスムーズに遷移することを期待する: UI 要素 動きが現れたり消えたりするのではなく、徐々にフェードインとフェードアウト スムーズに開始/停止するのではなく スムーズに終了できますAndroid プロパティ アニメーション フレームワークにより、スムーズな遷移が容易になります。

アニメーション システムを使用するには、プロパティに変更が加えられるたびに プロパティを直接変更しないでください。代わりに、 ValueAnimator で変更します。以下の例では、 ビュー内で選択された子コンポーネントを変更すると、レンダリング全体が 選択ポインタが中央に来るようにビューが回転します。 ValueAnimator は、数百の時間でローテーションを変更します。 ミリ秒未満で更新することをおすすめします。

Kotlin

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

Java

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0);
autoCenterAnimator.setIntValues(targetAngle);
autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
autoCenterAnimator.start();

変更する値がベース View のいずれかの場合 ビューに組み込み関数があるため、アニメーションの実行はさらに簡単です。 ViewPropertyAnimator 複数のプロパティの同時アニメーションに最適化されています。 次の例をご覧ください。

Kotlin

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

Java

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();