Как вызвать эффект пульсации на Android Lollipop в определенном месте в представлении, не вызывая прикосновения к событиям?
Это короткий вопрос:
Предположим, что у меня есть View
с RippleDrawable
в качестве фона.
Есть ли простой способ вызвать пульсацию из определенной позиции без запуска каких-либо событий касания или кликов?
Ответы
Ответ 1
Да, есть! Чтобы запрограммировать пульсацию программно, вам необходимо установить состояние RippleDrawable
с помощью setState()
. Вызов setVisible()
работает НЕ!
Решение
Чтобы показать пульсацию, вы должны одновременно нажимать и включать состояние:
rippleDrawable.setState(new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled });
Шум будет отображаться до тех пор, пока будут установлены эти состояния. Если вы хотите скрыть пульсацию, снова установите состояние на пустой int[]
:
rippleDrawable.setState(new int[] { });
Вы можете установить точку, из которой вытекает пульсация, вызывая setHotspot()
.
Как это работает
Я много отлаживал и изучал исходный код RippleDrawable
вверх и вниз, пока не понял, что пульсация действительно срабатывает в onStateChange()
. Вызов 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;
}
Как вы можете видеть, установлены ли как активированный, так и нажатый атрибут, будут активированы пульсация и фон, и будет отображаться пульсация.
Кроме того, если вы установили сфокусированное состояние, фон также будет активирован. С этим вы можете вызвать пульсацию и независимо изменить цвет фона.
Если вам интересно, вы можете просмотреть весь исходный код RippleDrawable
здесь.
Ответ 2
Я включил/объединил ответы от @Xaver Kapeller и @Nikola Despotoski выше:
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(), передав представление, которое вы хотите пульсировать как параметр.
Ответ 3
Во-первых, вам нужно получить извлечение из представления.
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)
сделает видимый и последний аргумент drawable, который заставит анимацию независимо от текущего текущего состояния.
Ответ 4
Вот сочетание Nikola setHotSpot() и fooobar.com/questions/332332/...
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);
}
Ответ 5
Я использовал следующий 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()
}
}