使涟漪填满整个视图

10

在我的应用程序中,我想要创建一个覆盖整个视图的涟漪效果。由于它没有正常工作,我创建了一个最小的示例应用程序,并在那里尝试了一下,但是没有成功。

我的布局看起来像这样:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent" android:padding="16dp">

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/ripple"
        android:onClick="onViewClicked" />

</LinearLayout>

我的drawable定义如下:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#1E88E5"
    android:radius="0dp">

    <item
        android:id="@android:id/mask"
        android:drawable="@android:color/white" />

</ripple>
这里有一个视频,展示了目前的表现。我希望圆圈(我认为它在官方上被称为热点)从中间开始增大,直到填满整个View。我说的不是波纹的半径,在这里有意设置为0dp。您有什么想法可以实现这一点吗? 编辑:最终我想实现像这样的效果。
对于不想阅读所有答案的人:我成功地实现了它,并为此创建了一个存储库。请随意在您的项目中使用它并向我发送拉取请求。

你在实际的真机测试设备上有哪些API?不幸的是,我认为它(RippleDrawable)只适用于API 21+(Android 5.0,LOLLIPOP)。支持库21仍无法使其在旧设备上运行。 - Jon Goodwin
是的,你说得对。我在API 26 Oreo上测试过了。如果真正的解决方案能在API 14+上运行就太好了。 - Cilenco
我想我见过一个可以做到这个的库,如果我找到了,我会联系你。 - Jon Goodwin
@Cilenco 试着使用这个android:background="?android:attr/selectableItemBackground"。如果你可以接受使用库,请看看这个网址https://android-arsenal.com/tag/167 - PN10
https://github.com/traex/RippleEffect 库是我测试过的最好的库。易于实现且支持 API 14+。 - Jon Goodwin
3个回答

7

您可以通过创建自定义的RippleView来实现此效果。使用onDraw方法在整个视图上绘制圆形,并将动画设置为该圆形。

if (animationRunning) {
            canvas.save();
            if (rippleDuration <= timer * frameRate) {
                animationRunning = false;
                timer = 0;
                durationEmpty = -1;
                timerEmpty = 0;
                // There is problem on Android M where canvas.restore() seems to be called automatically
                // For now, don't call canvas.restore() manually on Android M (API 23)
                if(Build.VERSION.SDK_INT != 23) {
                    canvas.restore();
                }
                invalidate();
                if (onCompletionListener != null) onCompletionListener.onComplete(this);
                return;
            } else
                canvasHandler.postDelayed(runnable, frameRate);

            if (timer == 0)
                canvas.save();


            canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);

            paint.setColor(Color.parseColor("#ffff4444"));

            if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {
                if (durationEmpty == -1)
                    durationEmpty = rippleDuration - timer * frameRate;

                timerEmpty++;
                final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));
                canvas.drawBitmap(tmpBitmap, 0, 0, paint);
                tmpBitmap.recycle();
            }

            paint.setColor(rippleColor);

            if (rippleType == 1) {
                if ((((float) timer * frameRate) / rippleDuration) > 0.6f)
                    paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));
                else
                    paint.setAlpha(rippleAlpha);
            }
            else
                paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));

            timer++;
        }

这个实现是从RippleEffect Library项目中偷来的。在库项目中找到完整的实现。

要仅从中心位置创建圆,请使用以下方法

 /**
     * Launch Ripple animation for the current view centered at x and y position
     *
     * @param x Horizontal position of the ripple center
     * @param y Vertical position of the ripple center
     */
    public void animateRipple(final float x, final float y) {
        createAnimation(x, y);
    }



/**
 * Create Ripple animation centered at x, y
 *
 * @param x Horizontal position of the ripple center
 * @param y Vertical position of the ripple center
 */
private void createAnimation(final float x, final float y) {
    if (this.isEnabled() && !animationRunning) {
        if (hasToZoom)
            this.startAnimation(scaleAnimation);

        radiusMax = Math.max(WIDTH, HEIGHT);

        if (rippleType != 2)
            radiusMax /= 2;

        radiusMax -= ripplePadding;

        if (isCentered || rippleType == 1) {
            this.x = getMeasuredWidth() / 2;
            this.y = getMeasuredHeight() / 2;
        } else {
            this.x = x;
            this.y = y;
        }

        animationRunning = true;

        if (rippleType == 1 && originBitmap == null)
            originBitmap = getDrawingCache(true);

        invalidate();
    }
}

输出:

您可以获得从中间开始增长直到填满整个视图的圆圈。

enter image description here

非常感谢您提供这个出色的答案。我已经自己实现了它,并为此创建了一个repo。我使用了API 11中的Animation类,不像库中那样自己计算所有内容,因此请自行决定哪个版本最适合您。 - Cilenco

2

可点击视图的涟漪效应

在API 21中,常规按钮的涟漪效应将默认起作用,对于其他可触摸视图,可以通过指定以下代码来实现:

    android:background="?android:attr/selectableItemBackground">
Java代码中的写法为:
int[] attrs = new int[]{R.attr.selectableItemBackground}; TypedArray typedArray = getActivity().obtainStyledAttributes(attrs); int backgroundResource = typedArray.getResourceId(0, 0); myView.setBackgroundResource(backgroundResource);

按钮
Button Image

大多数按钮都由几个Drawable组成。通常,您将具有类似以下资产的按下和正常版本:
/drawable/button.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/button_pressed"/>
    <item android:drawable="@drawable/button_normal"/>
</selector>

如果您有一个带有选定状态的自定义按钮,那么文本颜色会根据状态而改变,等等。因此,默认按钮背景在这里不起作用。您可以通过简单地将它们包装在涟漪元素中,为自己的可绘制对象和自定义按钮添加此反馈:
/drawable-v21/button.xml:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item android:drawable="@drawable/button_normal" />
</ripple>
使用?android:colorControlHighlight将使涟漪与应用程序中内置的涟漪颜色相同。

如果您不喜欢默认的灰色,您可以在主题中指定要使用的android:colorControlHighlight颜色。
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
    <item name="android:colorControlHighlight">@color/your_custom_color</item>
  </style>

</resources>

如果您希望涟漪效果超出视图边界,则可以使用?attr/selectableItemBackgroundBorderless。这对于ImageButtons和作为较大View的一部分的较小按钮非常有效。

0

尝试这个,希望对你有用

使用 android:foreground="@drawable/ripple"

而不是 android:background="@drawable/ripple"

并且改变 android:radius="0dp" 为50dp或100dp并检查


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接