在透明自定义按钮视图上获得涟漪效应

Get ripple effect on transparent custom button view

我正在制作一个具有渐变边框、圆角和透明背景的自定义按钮视图。我将按钮的背景设置为由以下代码生成的可绘制对象:

protected Drawable getBackgroundDrawable() {
    GradientDrawable backgroundDrawable = new GradientDrawable(
            mOrientation,
            mGradientColors);
    backgroundDrawable.setCornerRadius(getHeight() / 2);
    backgroundDrawable.setShape(GradientDrawable.RECTANGLE);

    if (!mFilled) {
        Bitmap background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas backgroundCanvas = new Canvas(background);
        backgroundCanvas.drawARGB(0, 0, 0, 0);
        backgroundDrawable.setBounds(0, 0, getWidth(), getHeight());
        backgroundDrawable.draw(backgroundCanvas);

        Paint rectPaint = new Paint();
        rectPaint.setAntiAlias(true);
        rectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        backgroundCanvas.drawRoundRect(new RectF(mStroke, mStroke,
                        getWidth() - mStroke,
                        getHeight() - mStroke),
                getHeight() / 2,
                getHeight() / 2,
                rectPaint);

        return new BitmapDrawable(getResources(), background);
    } else {
        return backgroundDrawable;
    }
}

唯一的问题是,当你现在点击按钮时,你没有反馈。当我已经使用生成的可绘制对象作为背景时,如何在按钮后面添加波纹效果?我必须对 LayerDrawable 做些什么吗?

我的按钮是这样的:

我真正想要达到的目标

以编程方式创建一个与此 XML 可绘制对象具有相同结果的可绘制对象,其中涟漪元素中的项目是我在上图中生成的可绘制对象:

<ripple android:color="@android:color/black" xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/background"></item>
</ripple>

我试过的

我现在尝试将 RippleDrawable 与 GradientDrawable 结合使用,以在代码中重新创建上面的 XML。很简单,我想:

GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.TRANSPARENT);
gradientDrawable.setStroke(mStroke, Color.GREEN);
gradientDrawable.setCornerRadius(getHeight() / 2);

ColorStateList rippleStateList = ColorStateList.valueOf(Color.BLUE);
return new RippleDrawable(rippleStateList, gradientDrawable, gradientDrawable);

这个 returns 带有绿色描边的简单绘图。但是,当您单击它时,什么也没有发生。与 XML 不同,您可以清楚地看到边界上的涟漪效应。当我将第三个参数设置为null时,同样的效果。当我只将第二个参数设置为 null 时,它只返回一个空的透明可绘制对象,没有任何波纹效果。

您应该使用 RippleDrawable 作为自定义按钮的背景。 RippleDrawable 有一个遮罩层,这就是你要找的。要以编程方式执行此操作,您可以像这样创建一个 RippleDrawable

float[] outerRadii = new float[8];
Arrays.fill(outerRadii, height / 2);

RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
ShapeDrawable mask = new ShapeDrawable(shape);

ColorStateList stateList = ColorStateList.valueof(ContextCompat.getColor(getContext(), R.color.ripple));

setBackground(new RippleDrawable(stateList, getBackgroundDrawable(), mask);

请记住,RippleDrawable 仅适用于 API 级别 21+,因此如果您希望同时支持旧版本,则需要回退到其他版本;可能 android.R.attr.selectableItemBackground or a StateListDrawable,这将为您的按钮提供针对旧平台版本的基本 "pressed" 背景。