Достичь пункт меню панели инструментов нажмите ripple effect

Я пытаюсь использовать 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 нажмите эффект больше не отображается как идеальный круг.

enter image description here


Я пытаюсь использовать 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>

enter image description here

теперь

  1. область щелчка увеличена.
  2. на selectableItemBackgroundBorderless круг эффект-идеальный круг.

однако, похоже, у него какое-то странное поведение. Когда я нажимаю на фактическую площадь ImageButton, эффект нажатия круга не отображается.

enter image description here

Примечание, я стараюсь избегать использования TouchDelegate техника, если я буду вынужден, как это делает наш код более сложный.


дополнительная информация

следующее правильное поведение, показанное кнопкой для Toolbar.

эффект пульсации отображается, когда область щелчка находится вне кнопки

enter image description here

эффект проявляется при щелчке в районе кнопки

enter image description here

тем не менее, я понятия не имею как они реализуют такое поведение.

4 ответов


потратив некоторое время, я, наконец, нашел, как "панели инструментов тайна" строительство. Это ActionMenuItemView, который отображается на панели инструментов. И вы можете видеть, что внутри xml-файл это 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" />

вы получите этот вывод:

enter image description here

включен "показать границы макета", так что фактические границы 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

чтобы исправить это, вам нужно использовать setHotspot() метод, добавленный к Drawable в API уровня 21. setHotspot() предоставляет в папке drawable в "горячая точка", и RippleDrawable по-видимому, использует это как точку эманации для эффекта пульсации. setHotspot() займет пару значения float, предположительно с прицелом на использование setHotspot() внутри OnTouchListener, как MotionEvent отчеты X/Y позиции события touch со значениями 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);
          }
     });
}

другое решение:

как добиться анимация пульсаций с помощью библиотеки поддержки?

RippleDrawable


другое решение:

С первой попытки:

я пытаюсь использовать прокладку для увеличения сенсорной области кнопки.

вы можете использовать этот код, чтобы поместить центр пульсация в центре 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, эффект кругового нажатия не отображается.

обойти эту проблему можно, чтобы добавить frameLayout.performClick() на onClick() метод ImageButton

или вы можете имитировать прикосновение 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);

если вы используете android:duplicateParentState="true", просто набор android:clickable="false" на ImageButton сделает ваш Button выделяем жмем на него и его родителей

<ImageButton
       ...
       android:duplicateParentState="true"
       android:clickable="false"
  />

объяснение

С документ

для дублирования включена, такая точка зрения государственного выигрышного от своих родителей, а не от собственных внутренних свойств

=> просмотр базы изменения состояния в Родительском состоянии. Значение по умолчанию clickable of ImageButton is true => при нажатии кнопки ImageButton, состояние родителя не изменяется => ImageButton не выделить

= > Set 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 для родительского макета


Я подозреваю, что ваша проблема заключается в том, что у вас есть 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, или установите элемент, чтобы быть не кликабельным и фокусируемым вручную. Также важно установить прослушиватель кликов на контейнере,не в сама кнопка / изображение, потому что она станет кликабельной.

это один из вариантов:

<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>

другой такой же, за исключением вида внутри 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"
    />

вот визуальное доказательство:

screen capture

это было захвачено на эмуляторе под управлением Android 5.0.2. Я попробовал это на своем телефоне 8.0, также работает.