1.概述
最近看到网易云音乐的听歌识曲的页面,这次仿网易云音乐听歌识曲效果。
2.效果
1.水波纹效果
3.实现思路
1.我们通过自定义一个容器,以及自定义水波纹的圆。
2.自定义的容器添加几个自定义属性,水波纹颜色,半径,边宽等。
3.在我们自定义容器中获取自定义属性,并创建添加水波纹的圆。我这里设置为4个。
4.处理水波纹的圆是有X/Y轴的缩放动画。以及透明度的动画。
4.代码实现
4.1自定义属性
4.2自定义容器
/**
* TODO:自定义容器,动态添加水波纹的圆。并通过动画实现
* 实现步骤
* 1.通过自定义属性来设置背景,以及水波纹颜色等
* 2.动态添加水波纹个数
* 3.通过动画实现水波纹的XY轴缩放,以及透明度的变化
*/
public class RippleAnimationView extends RelativeLayout {
//画笔
public Paint paint;
//水波纹半径
private int radius;
//水波纹颜色
private int rippleColor;
//水波纹描边宽度
private int strokWidth;
//水波纹的类型,0-实心充满 1-空心描边
private int rippleType;
//动画集合
private AnimatorSet animatorSet;
//水波纹圆的集合
private ArrayList viewList = new ArrayList<>();
//动画执行的标志位
private boolean animationRunning = false;
public RippleAnimationView(Context context) {
this(context,null);
}
public RippleAnimationView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public RippleAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context, AttributeSet attrs) {
//解析自定义属性
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.RippleAnimationView);
radius = array.getInteger(R.styleable.RippleAnimationView_radius, 54);
rippleColor = array.getColor(R.styleable.RippleAnimationView_ripple_anim_color, ContextCompat.getColor(context, R.color.rippleColor));
strokWidth = array.getInteger(R.styleable.RippleAnimationView_strokWidth,2);
rippleType = array.getInt(R.styleable.RippleAnimationView_ripple_anim_type, 0);
//初始化画笔
paint = new Paint();
paint.setAntiAlias(true); //设置抗锯齿
paint.setStrokeWidth(UIUtils.getInstance().getWidth(strokWidth)); //设置描边宽度
if (rippleType == 0){
paint.setStyle(Paint.Style.FILL);//设置样式
}else {
paint.setStyle(Paint.Style.STROKE);
}
paint.setColor(rippleColor); //设置颜色
//动态添加水波纹,设置它的大小
LayoutParams rippleParams = new LayoutParams(UIUtils.getInstance().getWidth(radius + strokWidth),UIUtils.getInstance().getWidth(radius + strokWidth));
rippleParams.addRule(CENTER_IN_PARENT, TRUE);
//设置最大缩放系数
float maxScale = 10;//UIUtils.getInstance().displayMetricsWidth / (float) ( (UIUtils.getInstance().getWidth(radius + strokWidth)));
//动画执行时间
int rippleDuration = 3500;
//间隔时间 (上一个波纹 和下一个波纹的)
int singleDelay = rippleDuration / 4;
//动画的集合,使用AnimatorSet
ArrayList animatorList = new ArrayList<>();
//实例化一个波纹=view
for (int i = 0; i < 4; i++) {
//创建一个水波纹的View,添加到当前容器
RippleCircleView rippleCircleView = new RippleCircleView(this);
viewList.add(rippleCircleView);
//设置属性动画X轴,Y轴缩放动画,以及透明度动画
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleCircleView, View.SCALE_X,maxScale,0);
scaleXAnimator.setRepeatCount(ObjectAnimator.INFINITE); //无线重复
scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART);
scaleXAnimator.setStartDelay(i * singleDelay);
scaleXAnimator.setDuration(rippleDuration);
animatorList.add(scaleXAnimator);
//Y轴缩放
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(rippleCircleView, View.SCALE_Y,maxScale,0);
scaleYAnimator.setRepeatCount(ObjectAnimator.INFINITE);
scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART);
scaleYAnimator.setStartDelay(i * singleDelay);
scaleYAnimator.setDuration(rippleDuration);
animatorList.add(scaleYAnimator);
//透明度
ObjectAnimator alphaYAnimator = ObjectAnimator.ofFloat(rippleCircleView, View.ALPHA,0f,1f);
alphaYAnimator.setRepeatCount(ObjectAnimator.INFINITE);
alphaYAnimator.setRepeatMode(ObjectAnimator.RESTART);
alphaYAnimator.setStartDelay(i * singleDelay);
alphaYAnimator.setDuration(rippleDuration);
animatorList.add(alphaYAnimator);
addView(rippleCircleView,rippleParams);
}
animatorSet = new AnimatorSet();
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); //先加速后减速
//同时执行动画
animatorSet.playTogether(animatorList);
array.recycle();
}
public int getStrokWidth() {
return strokWidth;
}
/**
* TODO:开始动画
*/
public void startRippleAnimation(){
if (!animationRunning){ //如果没有执行动画的时候需要隐藏水波纹
for (RippleCircleView rippleView : viewList) {
rippleView.setVisibility(VISIBLE);
}
animatorSet.start();
animationRunning = true;
}
}
/**
* TODO:开始动画
*/
public void stopRippleAnimation(){
if (animationRunning){
Collections.reverse(viewList); //将它反序
for (RippleCircleView rippleView : viewList) {
rippleView.setVisibility(INVISIBLE);
}
animatorSet.end();
animationRunning = false;
}
}
public boolean isAnimationRunning() {
return animationRunning;
}
public void setAnimationRunning(boolean animationRunning) {
this.animationRunning = animationRunning;
}
}
4.3自定义水波纹的圆
/**
* TODO:自定义水波纹的圆
*/
public class RippleCircleView extends View {
//持有父容器的RippleAnimationView的引用
private RippleAnimationView rippleAnimationView;
public RippleCircleView(RippleAnimationView rippleAnimationView) {
this(rippleAnimationView.getContext(),null);
this.rippleAnimationView = rippleAnimationView;
this.setVisibility(View.INVISIBLE); //默认隐藏
}
public RippleCircleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public RippleCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 画圆
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
int radius = (Math.min(getWidth(), getHeight())) / 2;
canvas.drawCircle(radius,radius,radius - rippleAnimationView.getStrokWidth(),rippleAnimationView.paint);
}
}
5.使用
5.1.布局文件
5.2.Activity中使用
/**
* TODO:仿网易云音乐听歌识曲水波纹效果
*/
public class RippleActivity extends AppCompatActivity {
private ActivityRippleBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_ripple);
//这个是用于做屏幕适配的,设置中间图片的大小
ViewCalculateUtil.setViewLayoutParam(binding.ImageView, 300,300,0,0,0,0);
//设置点击事件
binding.ImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//如果动画正在执行,那么就暂停,否则开启
if (binding.layoutRippleAnimation.isAnimationRunning()){
binding.layoutRippleAnimation.stopRippleAnimation();
}else {
binding.layoutRippleAnimation.startRippleAnimation();
}
}
});
}
}