web-dev-qa-db-ja.com

タッチイベントをトリガーせずに、ビュー内の特定の場所でAndroid Lollipopに波及効果をトリガーする方法は?

これは短い質問です:

Viewを背景としてRippleDrawableがあるとします。

タッチイベントやクリックイベントをトリガーせずに、特定の位置からリップルをトリガーする簡単な方法はありますか?

23

はいあります!プログラムでリップルをトリガーするには、RippleDrawableの状態をsetState()で設定する必要があります。 setVisible()を呼び出すと[〜#〜]動作しません[〜#〜]は機能しません!


ソリューション

リップルを表示するには、状態を押すと同時に有効にするように設定する必要があります。

_rippleDrawable.setState(new int[] { Android.R.attr.state_pressed, Android.R.attr.state_enabled });
_

これらの状態が設定されている限り、リップルが表示されます。リップルを再度非表示にする場合は、状態を空に設定します_int[]_:

_rippleDrawable.setState(new int[] {  });
_

setHotspot()を呼び出すことにより、リップルが発生するポイントを設定できます。


使い方

onStateChange()でリップルが実際にトリガーされることに気付くまで、私は多くのデバッグを行い、RippleDrawableのソースコードを上下に調べました。 setVisible()を呼び出しても効果はなく、実際にリップルが発生することはありません。

RippleDrawableのソースコードの関連部分は次のとおりです。

_@Override
protected boolean onStateChange(int[] stateSet) {
    final boolean changed = super.onStateChange(stateSet);

    boolean enabled = false;
    boolean pressed = false;
    boolean focused = false;

    for (int state : stateSet) {
        if (state == R.attr.state_enabled) {
            enabled = true;
        }
        if (state == R.attr.state_focused) {
            focused = true;
        }
        if (state == R.attr.state_pressed) {
            pressed = true;
        }
    }

    setRippleActive(enabled && pressed);
    setBackgroundActive(focused || (enabled && pressed));

    return changed;
}
_

Enabled属性とpressed属性の両方が設定されているかどうかを確認できるように、リップルとバックグラウンドの両方がアクティブになり、リップルが表示されます。さらに、フォーカスされた状態を設定している限り、背景もアクティブになります。これにより、波紋をトリガーして、背景の色を個別に変更できます。

興味がある場合は、RippleDrawablehere のソースコード全体を表示できます。

31
Xaver Kapeller

上記の@XaverKapellerと@NikolaDespotoskiからの回答を組み込み/組み合わせました。

protected void forceRippleAnimation(View view)
{
    Drawable background = view.getBackground();

    if(Build.VERSION.SDK_INT >= 21 && background instanceof RippleDrawable)
    {
        final RippleDrawable rippleDrawable = (RippleDrawable) background;

        rippleDrawable.setState(new int[]{Android.R.attr.state_pressed, Android.R.attr.state_enabled});

        Handler handler = new Handler();

        handler.postDelayed(new Runnable()
        {
            @Override public void run()
            {
                rippleDrawable.setState(new int[]{});
            }
        }, 200);
    }
}

プログラムでコマンドに波及効果を強制するには、forceRippleAnimation()を呼び出して、波及させたいビューをパラメーターとして渡します。

18
Luke

まず、ビューからドローアブルを取得する必要があります。

_private void forceRippleAnimation(View v, float x, float y){
   Drawable background = v.getBackground();
   if(background instanceof RippleDrawable){
     RippleDrawable ripple = (RippleDrawable)background;
     ripple.setHotspot(x, y);
     ripple.setVisible (true, true);
   }

}
_

メソッドsetHotspot(x,y);は、リップルアニメーションを開始する場所を設定するために使用されます。設定されていない場合、RippleDrawableは、それが存在するRect(つまり、背景として設定されているビューのRect)を取得します。波及効果を中心から開始します。

setVisible(true, true)はドローアブルを表示し、最後の引数は現在のドローアブルの状態に関係なくアニメーションを強制します。

7

これがニコラのsetHotSpot()と https://stackoverflow.com/a/25415471/147411 の組み合わせです

private void forceRipple(View view, int x, int y) {
    Drawable background = view.getBackground();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop && background instanceof RippleDrawable) {
        background.setHotspot(x, y);
    }
    view.setPressed(true);
    // For a quick ripple, you can immediately set false.
    view.setPressed(false);
}
7
ypresto

Lukeのコードの次のKotlinバリアントを使用して、RecyclerViewからセルをスワイプするときにリップルを手動で表示および非表示にしました。

fun View.showRipple() {
    if (Build.VERSION.SDK_INT >= 21 && background is RippleDrawable) {
        background.state = intArrayOf(Android.R.attr.state_pressed, Android.R.attr.state_enabled)
    }
}

fun View.hideRipple() {
    if (Build.VERSION.SDK_INT >= 21 && background is RippleDrawable) {
        background.state = intArrayOf()
    }
}
0
Pontomedon