RippleDrawable 触摸反馈 ---- java 代码编写

默认效果(有界 & 无界)

  1. 有界: ?Android:attr/selectableItemBackground
  2. 无界: ?android:attr/selectableItemBackgroundBorderless

用 xml 自己编写一个无界波纹

<?xml version="1.0" encoding="utf-8"?>

用 xml 自己编写一个有界波纹

<?xml version="1.0" encoding="utf-8"?>    

代码编写 RippleDrawable

1. 首先看 RippleDrawable 类的构造函数

//xml 中编写的话会执行此无参构造函数RippleDrawable() {        this(new RippleState(null, null, null), null);    }
//代码编写使用有参构造函数public RippleDrawable(@NonNull ColorStateList color, @Nullable Drawable content,            @Nullable Drawable mask) {        this(new RippleState(null, null, null), null);        //color: 波纹的颜色,必须要有,没有直接抛异常,程序崩溃        if (color == null) {            throw new IllegalArgumentException("RippleDrawable requires a non-null color");        }        //content: 背景,当背景为null时,波纹为无界.不为null时为有界.        if (content != null) {            addLayer(content, null, 0, 0, 0, 0, 0);        }        //mask: 按照说明,mask是不会被draw的,但是它会限制波纹的边界,如果为null,默认为content的边界,同上,当content为null就没有边界了.        if (mask != null) {            addLayer(mask, null, android.R.id.mask, 0, 0, 0, 0);        }        //省略无关代码...    }

2. 按照构造参数,提供需要的参数

  • ColorStateList color
  • Drawable content
  • Drawable mask

我写了个简单的:

RippleDrawable drawable=new RippleDrawable(                ColorStateList.valueOf(Color.GRAY),//灰色波纹                getResources().getDrawable(R.drawable.shape_cricle_solid_whote_stoke_gray),//一个圆角5dp,白色填充,灰色边框的shape图形,在xml中定义的                getShape()//编写了一个方法来获取mask        );

用代码编写shape在下文会提到.
上面用到的shape xml:

<?xml version="1.0" encoding="utf-8"?>            

这里我们的重点放在 mask 的形状上,因为上面说过,mask 会限制波纹扩散的边界,一般情况我们是不需要额外定义的,我们都是拿一个View的背景来作为波纹边界----就是RippleDrawable第二个参数 Drawable content.我们试着去定义,看看实际的限制是如何的.

自定义波纹边界

我的getshape()方法写了一个见到的shape:

    private Drawable getShape(){        ShapeDrawable mask =new ShapeDrawable(new RectShape(){            @Override            public void draw(Canvas canvas, Paint paint) {                final float width = this.getWidth();                final float height = this.getHeight();                //我想在这个矩形的区域(这里是800px*800px正方形)里画一个 六芒星 ~{=.=}                //六芒星是上下两个三角形叠加的,所以我画两个三角形就行了.                //if width == height (为了显示好看,我们设置长宽一样,这里我就认为长宽一样了)                final float r = width /2 ;                PointF center = new PointF(width/2,height/2);                float offsetHeight = (float) (Math.sin(Math.toRadians(30)) * r);                float offsetWidth = (float) (Math.cos(Math.toRadians(30)) * r);                //画正三角形                Path up = new Path();                up.moveTo(center.x - offsetWidth,center.y + offsetHeight);                up.lineTo(center.x - offsetWidth,center.y + offsetHeight);                up.lineTo(center.x,0);                up.lineTo(center.x + offsetWidth,center.y + offsetHeight);                up.close();                canvas.drawPath(up,paint);                //画倒三角形                Path down =new Path();                down.moveTo(center.x - offsetWidth,center.y - offsetHeight);                down.lineTo(center.x - offsetWidth,center.y - offsetHeight);                down.lineTo(center.x,center.y * 2);                down.lineTo(center.x + offsetWidth ,center.y - offsetHeight);                down.close();                canvas.drawPath(down,paint);            }        });        return mask;    }

方法比较简单,就是连线,然后画出来.
最后的效果是这样的:


RippleDrawable mask

当然你有想法可以自己去实现,但是基本的就是这样了.嘿嘿

代码编写 Shape 图形

首先说一个误区,可能有人认为 Shape 图形对应的是 ShapeDrawable ,实际上不是的.这里搬一段源码比较好说明.

DrawableInflater 类有一个方法 inflateFromTag(String name):

    private Drawable inflateFromTag(@NonNull String name) {        switch (name) {            case "selector":                return new StateListDrawable();            case "animated-selector":                return new AnimatedStateListDrawable();            case "level-list":                return new LevelListDrawable();            case "layer-list":                return new LayerDrawable();            case "transition":                return new TransitionDrawable();            case "ripple":                return new RippleDrawable();            case "color":                return new ColorDrawable();            case "shape"://xml 中标签对应的是 GradientDrawable                return new GradientDrawable();            case "vector":                return new VectorDrawable();            case "animated-vector":                return new AnimatedVectorDrawable();            case "scale":                return new ScaleDrawable();            case "clip":                return new ClipDrawable();            case "rotate":                return new RotateDrawable();            case "animated-rotate":                return new AnimatedRotateDrawable();            case "animation-list":                return new AnimationDrawable();            case "inset":                return new InsetDrawable();            case "bitmap":                return new BitmapDrawable();            case "nine-patch":                return new NinePatchDrawable();            default:                return null;        }    }

所以对代码编写Shape图形:

GradientDrawable gradientDrawable=new GradientDrawable();        int dp50 = DisplayUtil.dp2px(this, 50);        gradientDrawable.setColor(Color.RED);        gradientDrawable.setCornerRadius(dp50);        gradientDrawable.setStroke(dp50/5,Color.BLACK);

这样就定义了一个填充色是红色,圆角是50dp,边线是10dp 黑色的Shape图形了.

关于 shape 和 RippleDrawable 再说两句

关于波纹的两层颜色:底层浅一些,上面一层暗一些,源码里是这样写的:

RippleDrawabledraw()方法里有用来花 background 与 ripple的方法 drawBackgroundAndRipples(canvas);

    private void drawBackgroundAndRipples(Canvas canvas) {        final RippleForeground active = mRipple;        final RippleBackground background = mBackground;                //省略无关代码...        //获取设置的颜色,默认是黑色        final int color = mState.mColor.getColorForState(getState(), Color.BLACK);        //获取设置颜色的一半透明度        final int halfAlpha = (Color.alpha(color) / 2) << 24;                //        final Paint p = getRipplePaint();        if (mMaskColorFilter != null) {            //波动时间取决于颜料的alpha值,因此我们需要将alpha通道推入颜色,并让滤镜处理全alpha颜色。            final int fullAlphaColor = color | (0xFF << 24);            mMaskColorFilter.setColor(fullAlphaColor);            p.setColor(halfAlpha);            p.setColorFilter(mMaskColorFilter);            p.setShader(mMaskShader);        } else {            final int halfAlphaColor = (color & 0xFFFFFF) | halfAlpha;            p.setColor(halfAlphaColor);            p.setColorFilter(null);            p.setShader(null);        }        //省略无关代码...    }

总结: 也就是这两层,实际上是 Ripple Color 和一半透明度的 Ripple Color;

第二点:
当你拿 Shape 图形作为 RippleDrawable的mask 时,注意,mask 的有效区域 是要被 Draw的,虽然最终是不会画在你所看到的View上,但是你定义的 Shape 被draw 的部分才能作为 波纹 的边界条件,否则限制无效

我就拿上面编写的shape图形说明:

GradientDrawable gradientDrawable=new GradientDrawable();        int dp50 = DisplayUtil.dp2px(this, 50);        //gradientDrawable.setColor(Color.RED);        gradientDrawable.setCornerRadius(dp50);        gradientDrawable.setStroke(dp50/5,Color.BLACK);

我注释掉设置填充色的这句,然后看看效果:

只有边框的情况

当我取消注释:

有边框和填充色的情况

有什么不对的欢迎指正,喜欢点个赞呗~~~~

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. android里设置图片透明。
  3. Android(安卓)对话框【Dialog】去除白色边框代码
  4. android 中使用单元测试 Junit的步骤
  5. android webview js 交互
  6. SAX进行实体解析XML(android)
  7. Android利用ProGuard混淆代码
  8. android常用的几个获取包或activity以及判断前后台等
  9. [置顶] Android开发之将Edittext输入弹出的软键盘设置搜索确定键

随机推荐

  1. Android存储系统之源码篇
  2. Android关机重启实现
  3. 自定义View系列教程08--滑动冲突的产生及
  4. Property Animation属性动画,还用补间动画
  5. 安卓基本常用控件: View
  6. Android(安卓)指纹识别开发实例
  7. Android HandlerThread 详解
  8. Android(安卓)Service生命周期及用法
  9. Android 常用工具
  10. (四)Android事件分发机制 - 总结篇