padding
を使用して、ボタンのタッチ領域を拡大しようとしています。私が使う
<ImageButton
Android:paddingRight="32dp"
Android:paddingEnd="32dp"
Android:id="@+id/confirm_image_button"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentEnd="true"
Android:layout_alignParentRight="true"
Android:layout_centerVertical="true"
Android:background="?selectableItemBackgroundBorderless"
Android:src="?attr/confirmIcon" />
クリックエリアが拡大されます。ただし、selectableItemBackgroundBorderless
クリック効果は完全な円として表示されなくなりました。
私はduplicateParentState
テクニックを使って克服しようとしています。
<FrameLayout
Android:clickable="true"
Android:paddingRight="32dp"
Android:paddingEnd="32dp"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentEnd="true"
Android:layout_alignParentRight="true"
Android:layout_centerVertical="true">
<ImageButton
Android:duplicateParentState="true"
Android:id="@+id/confirm_image_button"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:background="?selectableItemBackgroundBorderless"
Android:src="?attr/confirmIcon" />
</FrameLayout>
さて、
selectableItemBackgroundBorderless
円効果は完全な円です。しかし、奇妙な振る舞いをしているようです。 ImageButton
の実際の領域をクリックしても、サークルプレス効果が表示されません。
なぜそうなのか、どうすればそれを克服できるのかわかりますか? API 26を使用してテストしました
コードをより複雑にするため、強制されない限り、TouchDelegate
テクニックの使用を避けようとしていることに注意してください。
以下は、Toolbar
のボタンによって示される正しい動作です。
クリック領域がボタンの外側にある場合にリップル効果が表示されます
リップル効果は、クリック領域がボタン内にあるときに表示されます
しかし、私は彼らがそのような振る舞いをどのように実装するのかわかりません。
しばらく時間を費やした後、私は最終的に「ツールバーミステリー」の仕組みを見つけました。ツールバーに表示されているのはActionMenuItemView
です。そして、ご覧のように、内部では xml file にstyle="?attr/actionButtonStyle"
が適用されています。 ?attr/actionButtonStyle
は Widget.Material.ActionButton
に対応し、このスタイル内で<item name="background">?attr/actionBarItemBackground</item>
を確認できます。
同じ効果をImageButton
に適用したい場合は、Android:background="?attr/actionBarItemBackground"
を適用するだけです。したがって、次のxmlレイアウト:
<ImageButton
Android:id="@+id/confirm_image_button"
Android:layout_width="50dp"
Android:layout_height="50dp"
Android:background="?attr/actionBarItemBackground"
Android:src="@drawable/ic_check_black_24dp" />
次の出力が表示されます。
「レイアウト境界の表示」をオンにして、ImageButton
の実際の境界が表示されるようにします
?attr/actionBarItemBackground
が実際に何を表しているのか知りたい場合は、- ここにあります :
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:color="?attr/colorControlHighlight"
Android:radius="20dp" />
したがって、ドローアブルを作成し、それを背景としてImageButton
に適用できます。
Android 5.0の波紋は各ビューの中央から始まります。マテリアルデザインルールによれば、波紋はタッチイベントが発生した場所から始まるため、指から外側に流れるように見えますこれはAndroid 5.1で対処されましたが、Android 5.0のバグでした
これを修正するには、APIレベル21のDrawableに追加された
setHotspot()
メソッドを使用する必要があります。setHotspot()
は、ドローアブルに“ホットスポットを提供”、そしてRippleDrawable
は明らかにこれを波及効果の発散点として使用しています。setHotspot()
は、おそらくOnTouchListener
がfloat値を含むタッチイベントの_X/Y
_位置を報告するため、MotionEvent
内でsetHotspot()
を使用することを目的として、一対のfloat値を取ります。
ビジーコーダーのガイドブックのおかげで
このコードを使用して、さざ波のバグを修正できます。
_if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
btn.setOnTouchListener(new View.OnTouchListener() {
@TargetApi(Build.VERSION_CODES.Lollipop)
@Override
public boolean onTouch(View v, MotionEvent event) {
v.getBackground()
.setHotspot(event.getX(), event.getY());
return(false);
}
});
}
_
その他の解決策:
サポートライブラリを使用してリップルアニメーションを実現するには?
別の解決策:
最初の試み:
ボタンのタッチ領域を増やすためにパディングを使用しようとします。
このコードを使用して、リップルの中心をImageButton
の中心に配置できます:
_if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
btn.setOnTouchListener(new View.OnTouchListener() {
@TargetApi(Build.VERSION_CODES.Lollipop)
@Override
public boolean onTouch(View v, MotionEvent event) {
v.getBackground()
.setHotspot(v.getWidth()/2f, v.getHeight()/2f);//setting hot spot at center of ImageButton
return(false);
}
});
}
_
FrameLayout
がImageButton
をラップする場合の別の解決策:
あなたが言うように:
しかし、奇妙な振る舞いをしているようです。 ImageButtonの実際の領域をクリックしても、サークルプレス効果が表示されません。
この問題の回避策は、ImageButton
のframeLayout.performClick()
メソッドにonClick()
を追加することです。
または、frameLayout
がクリックされたときに、次のコードのようにImageButton
のタッチをシミュレートできます。
_// Obtain MotionEvent object
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis() + 100;
float x = 0.0f;// or x = frameLayout.getWidth()/2f
float y = 0.0f;// or y = frameLayout.getHeight()/2f
// List of meta states found here: developer.Android.com/reference/Android/view/KeyEvent.html#getMetaState()
int metaState = 0;
MotionEvent motionEvent = MotionEvent.obtain(
downTime,
eventTime,
MotionEvent.ACTION_UP,
x,
y,
metaState
);
// Dispatch touch event to view
frameLayout.dispatchTouchEvent(motionEvent);
_
あなたの問題は、ImageButton
だけではなくImageView
があることにあると思います。 ImageButton
のデフォルトスタイルは次のとおりです。
<style name="Widget.ImageButton">
<item name="Android:focusable">true</item>
<item name="Android:clickable">true</item>
<item name="Android:scaleType">center</item>
<item name="Android:background">@Android:drawable/btn_default</item>
</style>
置き換えられたのは背景ですが、アイテムはクリック可能でフォーカス可能のままです。あなたの例では、実際のアクティブなアイテムはコンテナなので、通常のImageView
を使用するか、アイテムを手動でクリックおよびフォーカスできないように設定できます。また、コンテナにクリックリスナーを設定することも重要ですnotボタン/画像自体。クリック可能になるためです。
これは1つのバリアントです。
<FrameLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:paddingEnd="48dp"
Android:focusable="true"
Android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
>
<ImageButton
Android:duplicateParentState="true"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:background="?selectableItemBackgroundBorderless"
Android:duplicateParentState="true"
Android:src="@drawable/ic_check_black_24dp"
Android:clickable="false"
Android:focusable="false"
/>
</FrameLayout>
もう1つは同じですが、FrameLayout
内のビューは次のとおりです。
<ImageView
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:background="?selectableItemBackgroundBorderless"
Android:duplicateParentState="true"
Android:src="@drawable/ic_check_black_24dp"
/>
ここに視覚的な証拠があります:
これは、Android 5.0.2を実行しているエミュレータでキャプチャされました。8.0の電話でこれを試しましたが、同様に機能します。
_Android:duplicateParentState="true"
_を使用する場合、_Android:clickable="false"
_をImageButton
に設定するだけで、Button
をクリックしてその親をハイライトします。
_<ImageButton
...
Android:duplicateParentState="true"
Android:clickable="false"
/>
_
ドキュメント から
複製が有効になっている場合、このビューは独自の内部プロパティからではなく、親から描画可能状態を取得します
=>親の状態に基づいて状態の変更を表示します。 clickable
のデフォルトのImageButton
はtrueです=> ImageButton
をクリックすると、親の状態は変更されません=> ImageButton
は強調表示されません
=>セット_clickable=false
_は問題を解決します
1)親のセット_clickable=true
_を忘れないでください
2)TextView
、ImageView
(またはデフォルトでclickable = falseが設定されているビュー)の場合、_clickable=false
_を設定する必要はありません。
3)注意してくださいsetOnClickListener
を使用するとき
_public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
_
setOnClickListener
を使用すると、setClickable(true)
も使用されるため、この場合はのみ親レイアウトにsetOnClickListener
を設定する必要があります