周末闲着无聊分享一个自己写的带呼吸效果的android水波纹自定义view

时间:2023-02-09 09:15:50


无图无真相,废话不多说先来看看最终效果:

周末闲着无聊分享一个自己写的带呼吸效果的android水波纹自定义view

用法:

1.导入自定义属性文件(将这个文件放在 res/values 下)

attrs.xml

<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--带旋转动画的ImageView-->
    <declare-styleable name="waterRipplesView">
        <!--波的总个数-->
        <attr name="waveCount" format="integer"/>
        <!--程序一开始就播放波纹涟漪动画-->
        <attr name="waveOnLoad" format="boolean"/>
        <!--波的颜色-->
        <attr name="waveColor" format="color"/>
    </declare-styleable>
</resources></span>

2.哈哈重点来啦 导入

WaterRipplesView.java

<span style="font-size:18px;">package com.example.waterWave;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import java.util.ArrayList;
import java.util.List;

/**
 * 水波纹效果
 * @author zihao
 * Email zihao131125@gmail.com
 *
 */

public class WaterRipplesView extends View {
    private Paint paint;//用于绘制水波的画笔
    private boolean isStarting = true;
    private List<Circle> circles = new ArrayList<Circle>();
    private int waveCount = 5;//波纹的总个数
    private int color = 0x00ce9b;//波纹的颜色

    private float breathDirection = 1;//呼吸方向(+1:变亮,-1:变暗)
    private float breathSpeed = 0.02f;//呼吸速度
    private boolean isBreathing = false;

    public WaterRipplesView(Context context) {
        super(context);
        init(context,null);
    }

    public WaterRipplesView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public WaterRipplesView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint = new Paint();

        /**
         * 获取xml的配置参数
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.waterRipplesView, 0, 0);
        try {
            waveCount = a.getInteger(R.styleable.waterRipplesView_waveCount, 3);
            isStarting = a.getBoolean(R.styleable.waterRipplesView_waveOnLoad,true);
            color = a.getColor(R.styleable.waterRipplesView_waveColor,0x00ce9b);
        } finally {
            a.recycle();
        }
    }


    private int a = 0;
    private float breath = 1f;//控制呼吸

    @Override
    public void onDraw(Canvas canvas) {

        float alphaSpeed;
        float radiusSpeed;
        float hw = getWidth()/2f;

        /**
         * 根据view的宽度计算半径和透明度的变化速度,(为了尽力保证半径和透明度同时达到最值:255是透明度的最大值)
         */
        if(hw >255f){
            radiusSpeed = hw/255f;
            alphaSpeed = 1f;
        }else {
            alphaSpeed = 255f/hw;
            radiusSpeed = 1f;
        }

        /**
         * 控制呼吸
         */
        if(isBreathing){
            breath=breath+breathSpeed*breathDirection;
            if(breath>1 ){
                breathDirection *= -1;//呼吸反向
                if(beforBreathIsAwave){
                    isBreathing = false;
                    isStarting = true;
                    breath = 1;
                }

            }else if(breath <0.001){
                breathDirection *= -1;//呼吸反向
                if(!beforBreathIsAwave){
                    isBreathing = false;
                    isStarting = false;
                    breath = 1;
                }
            }
        }


        /**
         * 当达到设定的波距或第一次运行时 添加一个新波
         */
        if (++a>= (hw/waveCount) || circles.size()<1){
            a = 0;
        Circle c = new Circle();
        c.setX(getWidth() / 2).setY(getHeight() / 2).setColor(color).setAlpha(255).setRadius(1);
        circles.add(c);
        }

        for (int i= 0;i< circles.size();i++){

            Circle temp = circles.get(i);
            if(isStarting){
            temp.setAlpha(temp.getAlpha() - alphaSpeed);//改变波的透明度
            if(temp.getAlpha() <0){
                temp.setAlpha(0);
            }
            temp.setRadius(temp.getRadius() + radiusSpeed);//增加波的半径
            }

            paint.setColor(temp.getColor());
            int tempAlpha = (int)(temp.getAlpha()*breath);//乘以breath是为了通过改变透明度达到呼吸的效果
            paint.setAlpha(tempAlpha<0?0:tempAlpha);
            canvas.drawCircle(temp.getX(), temp.getY(), temp.getRadius(), paint);//绘制波




            /**
             * 当波的半径大于本控件的宽大时删除这个波
             */
            if( temp.getRadius() >getWidth() || temp.getAlpha() <0){
                circles.remove(temp);
            }
        }
        invalidate();
    }

    //波开始/继续进行
    public void start() {
        isStarting = true;
        invalidate();
    }

    //波暂停
    public void stop() {
        isStarting = false;
        invalidate();

    }

    public boolean isStarting() {
        return isStarting;
    }

    private boolean beforBreathIsAwave = true;

    /**
     * 此方法调用一次波会呼吸一次
     */
    public synchronized void breath(){
        this.beforBreathIsAwave =  isStarting;
        if(beforBreathIsAwave){
            breath = 1;
            breathDirection =-1;
        }
        else {
            breath = 0.01f;
            breathDirection = 1;
        }
        start();
        isBreathing = true;

    }

    /**
     * 代表每个波的类
     */
    public class Circle{
        private float x;
        private float y;
        private int color;
        private float alpha;
        private float radius;

        public float getRadius() {
            return radius;
        }

        public Circle setRadius(float radius) {
            this.radius = radius;
            return this;
        }

        public float getX() {
            return x;
        }

        public Circle setX(float x) {
            this.x = x;
            return this;
        }

        public float getY() {
            return y;
        }

        public Circle setY(float y) {
            this.y = y;
            return this;
        }

        public int getColor() {
            return color;
        }

        public Circle setColor(int color) {
            this.color = color;
            return this;
        }

        public float getAlpha() {
            return alpha;
        }

        public Circle setAlpha(float alpha) {
            this.alpha = alpha;
            return this;
        }
    }
}</span>

3.在你的布局文件中引用

例如:

<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res/com.example.waterWave"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">

    <com.example.waterWave.WaterRipplesView
            android:id="@+id/wave"
            android:layout_width="180dp"
            android:layout_height="180dp"
            app:waveCount="5"
            app:waveOnLoad="true"
            app:waveColor="#00ce9b"/>

</LinearLayout>
</span>


github demo地址:https://github.com/HelloWorldZH/tools.git  或 https://github.com/HelloWorldZH/tools
好了,就这样吧 具体解释代码中的注释写的够清楚了 欢迎给我指出问题 Email:zihao131125@gmail.com