一、效果图
二、RippleDrawable基本概念介绍
(1)、RippleDrawable
RippleDrawable可以实现上面效果图中的水波纹效果,它是在API 21 中添加的,所以,低于21的版本中不可使用。它的继承关系如下:
根据上面的继承关系,我们可知,我们可以用它来做背景;RippleDrawable是有层级的——LayerDrawable的特性。
(2)、xml属性
RippleDrawable在xml中对应的是
(3)、ripple的特性
A touch feedback drawable may contain multiple child layers, including a special mask layer that is not drawn to the screen. A single layer may be set as the mask from XML by specifying its
android:id
value as[R.id.mask](https://developer.android.com/reference/android/R.id.html#mask)
. At run time, a single layer may be set as the mask usingsetId(..., android.R.id.mask)
or an existing mask layer may be replaced usingsetDrawableByLayerId(android.R.id.mask, ...)
.
- ripple可以对触摸事件作出相应的反馈,它可以包含多个item。
- 其中id 为 mask 的item 在初始化界面时不会直接绘制出来,而是在发生触摸之后才会绘制。
- mask 直译过来有遮罩的意思,它会限定水波纹的范围。
- 如果我们需要将 ripple 中的某个item设置为 mask , 在xml 中,直接为该item设置id属性即可——
android:id="@android:id/mask"
; 在Java代码中如果想替换现有的mask,可以通过 RippleDrawable中的setDrawableByLayerId(android.R.id.mask, newDrawable)
来实现。 - 没有指定mask ,并且也没有指定radius 时,会以控件宽高中的较大值为直径绘制水波纹,这样就必然会超出控件的范围,所以,这种效果也叫做 无界水波纹效果。
- 指定mask 后 ,id 为 mask 的item 中指定的drawable 可以限定水波纹的范围。
三、代码示例:
(1)、xml 中定义 ripple
下列代码依次对应效果图中的前6个。
- ripple_1.xml
- ripple_2.xml
- ripple_3.xml
- ripple_4.xml
-
- ripple_5.xml
-
- ripple_6.xml
-
(2)、java代码中定义ripple
下列代码依次对应效果图中的后五个
/**
* 作者:CnPeng
* 时间:2018/8/8
* 功用:Ripple使用示例
* 其他:
*/
public class RippleDrawableActivity extends AppCompatActivity {
ActivityRippleBinding mBinding;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_ripple);
initTv1RippleBG(R.color.f9cf87);
initTv2RippleBG();
initTv3RippleBG();
initTv4RippleBG();
initTv5RippleBG();
}
/**
* 作者:CnPeng
* 时间:2018/8/8 下午3:37
* 功用:xml中已经设置背景为 ripple_1.xml 为背景,此处是更改ripple_1中的颜色
* 说明:
*/
@SuppressLint("ClickableViewAccessibility")
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void initTv1RippleBG(final int colorResId) {
final RippleDrawable rippleDrawable = (RippleDrawable) mBinding.tvRippleBg1.getBackground();
mBinding.tvRippleBg1.setOnTouchListener(new View.OnTouchListener() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public boolean onTouch(View v, MotionEvent event) {
rippleDrawable.setHotspot(event.getX(), event.getY());
//如果radius小于控件的宽高中的大值,则,触摸超出radius的部分时,也只会在控件中心位置为起点以radius为半径绘制ripple
rippleDrawable.setRadius(200);
rippleDrawable.setColor(ColorStateList.valueOf(getResources().getColor(colorResId)));
return false;
}
});
}
/**
* 作者:CnPeng
* 时间:2018/8/8 下午12:02
* 功用:以代码的方式构建rippleDrawable为背景——没有设置mask
* 说明:http://www.tothenew.com/blog/ripple-effect-in-android/
* https://www.programcreek.com/java-api-examples/index.php?api=android.graphics.drawable.RippleDrawable
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initTv2RippleBG() {
int[][] stateList = new int[][]{
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_focused},
new int[]{android.R.attr.state_activated},
new int[]{}
};
//深蓝
int normalColor = Color.parseColor("#303F9F");
//玫瑰红
int pressedColor = Color.parseColor("#FF4081");
int[] stateColorList = new int[]{
pressedColor,
pressedColor,
pressedColor,
normalColor
};
ColorStateList colorStateList = new ColorStateList(stateList, stateColorList);
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, null, null);
mBinding.tvRippleBg2.setBackground(rippleDrawable);
}
/**
* 作者:CnPeng
* 时间:2018/8/8 下午12:02
* 功用:以代码的方式构建rippleDrawable为背景——有drawable,但不设置mask
* 说明:http://www.tothenew.com/blog/ripple-effect-in-android/
* https://www.programcreek.com/java-api-examples/index.php?api=android.graphics.drawable.RippleDrawable
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initTv3RippleBG() {
int[][] stateList = new int[][]{
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_focused},
new int[]{android.R.attr.state_activated},
new int[]{}
};
//深蓝
int normalColor = Color.parseColor("#303F9F");
//玫瑰红
int pressedColor = Color.parseColor("#FF4081");
int[] stateColorList = new int[]{
pressedColor,
pressedColor,
pressedColor,
normalColor
};
ColorStateList colorStateList = new ColorStateList(stateList, stateColorList);
Drawable drawable = getResources().getDrawable(R.drawable.act_attentioned);
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, drawable, null);
mBinding.tvRippleBg3.setBackground(rippleDrawable);
}
/**
* 作者:CnPeng
* 时间:2018/8/8 下午12:02
* 功用:以代码的方式构建rippleDrawable为背景——无drawable,设置mask
* 说明:http://www.tothenew.com/blog/ripple-effect-in-android/
* https://www.programcreek.com/java-api-examples/index.php?api=android.graphics.drawable.RippleDrawable
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initTv4RippleBG() {
int[][] stateList = new int[][]{
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_focused},
new int[]{android.R.attr.state_activated},
new int[]{}
};
//深蓝
int normalColor = Color.parseColor("#303F9F");
//玫瑰红
int pressedColor = Color.parseColor("#FF4081");
int[] stateColorList = new int[]{
pressedColor,
pressedColor,
pressedColor,
normalColor
};
ColorStateList colorStateList = new ColorStateList(stateList, stateColorList);
Drawable drawable = getResources().getDrawable(R.drawable.act_attentioned);
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, null, drawable);
mBinding.tvRippleBg4.setBackground(rippleDrawable);
}
/**
* 作者:CnPeng
* 时间:2018/8/8 下午12:02
* 功用:以代码的方式构建rippleDrawable为背景——有drawable,设置mask
* 说明:http://www.tothenew.com/blog/ripple-effect-in-android/
* https://www.programcreek.com/java-api-examples/index.php?api=android.graphics.drawable.RippleDrawable
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initTv5RippleBG() {
int[][] stateList = new int[][]{
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_focused},
new int[]{android.R.attr.state_activated},
new int[]{}
};
//深蓝
int normalColor = Color.parseColor("#303F9F");
//玫瑰红
int pressedColor = Color.parseColor("#FF4081");
int[] stateColorList = new int[]{
pressedColor,
pressedColor,
pressedColor,
normalColor
};
ColorStateList colorStateList = new ColorStateList(stateList, stateColorList);
float[] outRadius = new float[]{10, 10, 15, 15, 20, 20, 25, 25};
RoundRectShape roundRectShape = new RoundRectShape(outRadius, null, null);
ShapeDrawable maskDrawable = new ShapeDrawable();
maskDrawable.setShape(roundRectShape);
maskDrawable.getPaint().setColor(Color.parseColor("#000000"));
maskDrawable.getPaint().setStyle(Paint.Style.FILL);
ShapeDrawable contentDrawable = new ShapeDrawable();
contentDrawable.setShape(roundRectShape);
contentDrawable.getPaint().setColor(Color.parseColor("#f7c653"));
contentDrawable.getPaint().setStyle(Paint.Style.FILL);
//contentDrawable实际是默认初始化时展示的;maskDrawable 控制了rippleDrawable的范围
RippleDrawable rippleDrawable = new RippleDrawable(colorStateList, contentDrawable, maskDrawable);
mBinding.tvRippleBg5.setBackground(rippleDrawable);
}
}
(3)、activity_ripple.xml
四、总结
(1)、涟漪效果的应用现状
应用名称 | 是否应用涟漪效果 | 应用的位置 |
---|---|---|
知乎 | 有 | 在底部导航和首页列表中有应用 |
无 | 无 | |
微信 | 无 | 无 |
无 | 无 | |
支付宝 | 无 | 无 |
口碑 | 无 | 无 |
微博 | 无 | 无 |
美团 | 无 | 无 |
淘宝 | 有 | 消息列表和Dialog中的按钮 |
在查看了我自己常用的几款软件之后,发现,只有知乎和淘宝在局部使用了这个涟漪效果,这。。。似乎有点尴尬啊
(2)、参考文章:
http://www.tothenew.com/blog/ripple-effect-in-android/
https://developer.android.com/reference/android/graphics/drawable/RippleDrawable
https://www.programcreek.com/java-api-examples/index.php?api=android.graphics.drawable.RippleDrawable
(3)、代码地址
文中代码地址为:https://github.com/CnPeng/CnPengAndroid.git
文中内容对应其中的:b_35_rippleDrawable 文件夹
本文到此结束,谢谢观看!
如有不足,敬请指正!