Android案例手册 - 定位点圆形水波纹和椭圆水波纹

举报
芝麻粒儿 发表于 2022/06/26 15:11:48 2022/06/26
【摘要】 👉关于作者众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)欢迎关注公众号【空名先生】获取更多资源和交流! 👉前提这是小空坚持写的Android新手向系列,欢迎...

👉关于作者

众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!

专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)

欢迎关注公众号【空名先生】获取更多资源和交流!

👉前提

这是小空坚持写的Android新手向系列,欢迎品尝。

新手(√√√)

大佬(√)

👉实践过程

先看效果图

定位点圆形水波纹和椭圆水波纹.gif

在相关需求中需要定位医学听诊点,给予用户一个提示反馈。所以封装了一个View。

分为圆形效果和椭圆形效果,并且Java版本和Kotlin版本都有。

如图中,我们可以看出,水波纹一点点扩张且越远越淡,那么我们就知道怎么做了。

  1. 声明一个圆类,随着时间的推移这个圆的透明度和半径进行变化
  2. 声明一个圆类数组,然后隔一段时间创建一个圆类添加进数组
  3. 在onDraw中遍历数组绘制出来,判断当前时间距离创建时间大于多少秒就从圆类数组中删除即可。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <!--人物背景图-->
    <ImageView
        android:layout_width="600dp"
        android:layout_height="900dp"
        android:src="@drawable/weizhi_bg" />
 
    <cn.appstudy.customView.WaveViewJava
        android:id="@+id/testWaveViewJava"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_marginStart="150dp"
        android:layout_marginTop="420dp" />
 
    <cn.appstudy.customView.WaveOvalViewJava
        android:id="@+id/testWaveOvalViewJava"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_marginStart="260dp"
        android:layout_marginTop="520dp" />
 
</RelativeLayout>

然后代码中找到这个布局View的id,调用start方法即可。

😜WaveView-圆形

如下代码类

创建一个可控变量定为波纹从创建到校时的持续时间,当然这个变量完全可以供外部修改。

创建一个变量控制波纹创建的间隔。

创建圆的相关变量(半径,颜色,画笔等等)。

start()方法为启动方法,开启反复的Runnable,间隔时间就是波纹创建时间,里面写创建圆的逻辑。

创建圆类,将当前时间记录下来保存进去,圆类中提供两个方法,更新的当前时间减去创建时候保存的的“当前时间”,这个插值是越来越大的,那么就可以修改透明度和半径。

之后便是onDraw中遍历圆类的数组,判断当前的时间和圆类中保存的创建时间,大于设定持续时间的值则销毁,否则用画笔在canvas进行绘制。

Java版

/**
 * @author akitaka
 * @filename WaveViewJava
 */
public class WaveViewJava extends View {
    private long mDuration = 2000; // 一个波纹从创建到消失的持续时间
    /**
     * 插值器属性,可理解为指定动画如何变化的动动;有多种
     * LinearInterpolator--画从开始到结束,变化率是线性变化
     */
    private Interpolator mInterpolator = new LinearInterpolator();
    private float mInitialRadius;   // 初始波纹半径
    private float mMaxRadius;   // 最大波纹半径
    private Paint mPaint;
    private List<Circle> mCircleList = new ArrayList<>();//当前正在显示的圆集合
    private boolean mIsRunning;//绘制线程是否开始
    private int mSpeed = 500;   // 波纹的创建速度,每500ms创建一个
    private long mLastCreateTime;   //上一个创建圆的时间
    private boolean mMaxRadiusSet;   //如果设置了最大半径
    private float mMaxRadiusRate = 0.85f;   // 如果没有设置mMaxRadius,可mMaxRadius = 最小长度 * mMaxRadiusRate;
 
    public WaveViewJava (Context context) {
        super(context);
    }
    public WaveViewJava (Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  //抗锯齿
        mPaint.setColor(Color.WHITE);
        setPaintStyle(Paint.Style.FILL);  //填充式
    }
    /**
     * 波纹半径率
     * @param maxRadiusRate
     */
    public void setMaxRadiusRate(float maxRadiusRate) {
        this.mMaxRadiusRate = maxRadiusRate;
    }
    /**
     * 画笔颜色
     * @param color
     */
    public void setColor(int color) {
        mPaint.setColor(color);
    }
    /**
     * 初始半径
     * @param radius
     */
    public void setInitialRadius(float radius) {
        mInitialRadius = radius;
    }
    /**
     * 设置波纹持续时间
     * @param duration
     */
    public void setDuration(long duration) {
        this.mDuration = duration;
    }
    /**
     * 最大波纹半径
     * @param maxRadius
     */
    public void setMaxRadius(float maxRadius) {
        this.mMaxRadius = maxRadius;
        mMaxRadiusSet = true;
    }
    /**
     * 波纹创建速度
     * @param speed
     */
    public void setSpeed(int speed) {
        mSpeed = speed;
    }
    /**
     * 插值器,达到不同的效果
     * @param interpolator
     */
    public void setInterpolator(Interpolator interpolator) {
        mInterpolator = interpolator;
        if (mInterpolator == null) {
            mInterpolator = new LinearInterpolator();
        }
    }
    /**
     * 提供给外界 设置画笔风格
     * @param style
     */
    public void setPaintStyle(Paint.Style style) {
        mPaint.setStyle(style);
    }
    /**
     * 提供给外界开来是整个过程
     */
    public void start() {
        if (!mIsRunning) {
            mIsRunning = true;
            mCreateCircle.run(); //开线程
        }
    }
    /**
     * 停止
     */
    public void stop() {
        mIsRunning = false;
    }
    private Runnable mCreateCircle = new Runnable() {
        @Override
        public void run() {
            if (mIsRunning) {
                newCircle();
                postDelayed(mCreateCircle, mSpeed); // 每隔mSpeed毫秒创建一个圆
            }
        }
    };
    /**
     * 创建圆
     */
    private void newCircle() {
        long currentTime = System.currentTimeMillis();
        if (currentTime - mLastCreateTime < mSpeed) {
            return;
        }
        Circle circle = new Circle();
        mCircleList.add(circle);
        invalidate();   //重新调用onDraw绘制
        mLastCreateTime = currentTime;
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (!mMaxRadiusSet) {
            mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f;
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        Iterator<Circle> iterator = mCircleList.iterator();   //得带期遍历
        while (iterator.hasNext()) { //是否=还有元素
            Circle circle = iterator.next();//拿到下一个
            if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
                mPaint.setAlpha(circle.getAlpha());  //设置透明度
                canvas.drawCircle(getWidth() / 2, getHeight() / 2, circle.getCurrentRadius(), mPaint);  //设置半径
            } else {  //如果创建的时间大于最大  则移除
                iterator.remove();
            }
        }
        if (mCircleList.size() > 0) {
            postInvalidateDelayed(10);  //10毫秒刷新  快速给人错觉是动态的  其实是静态的很多圆
        }
    }
    /**
     * 绘制圆的类   getAlpha、getCurrentRadius插值器原因
     * 你可以在外部设置不同的插值器器,来实现波纹的不同动态效果;详情请学习插值器;
     */
    private class Circle {
        private long mCreateTime;  //当前添加圆时间
        public Circle() {
            this.mCreateTime = System.currentTimeMillis();
        }
        /**
         * 获得透明度  ↓0(消失)
         * getInterpolation传值越大,返回越大 因为是LinearInterpolator 传值返回一致
         * @return
         */
        public int getAlpha() {
            //当前时间处于总时间的百分比   当前时间/圆创建-消失总时间
            float percent = (float) ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration);
            return (int) ((1.0f - mInterpolator.getInterpolation(percent)) * 255);
        }
        /**
         * 获得当前的半径
         */
        public float getCurrentRadius() {
            float percent = (float) ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration);
            //最小半径+当前扩大百分比半径
            return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius);
        }
    }
}

Kotlin版

/**
 * Created by akitaka on 2022-06-22.
 * @author akitaka
 * @filename WaveViewKotlin
 * @describe
 * @email 960576866@qq.com
 */
class WaveViewKotlin : View {
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    var mDuration: Long = 2000 // 一个波纹从创建到消失的持续时间
    /**
     * 插值器属性,可理解为指定动画如何变化的动动;有多种
     * LinearInterpolator--画从开始到结束,变化率是线性变化
     */
    var mInterpolator: Interpolator = LinearInterpolator()
    var mInitialRadius = 0f// 初始波纹半径
    var mMaxRadius = 0f// 最大波纹半径
    var mPaint: Paint? = null
    var mCircleList: MutableList<Circle> = ArrayList() //当前正在显示的圆集合
    var mIsRunning = false//绘制线程是否开始
    var mSpeed = 500 // 波纹的创建速度,每500ms创建一个
    var mLastCreateTime: Long = 0//上一个创建圆的时间
    var mMaxRadiusSet = false//如果设置了最大半径
    var mMaxRadiusRate = 0.85f // 如果没有设置mMaxRadius,可mMaxRadius = 最小长度 * mMaxRadiusRate;

    init {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG);  //抗锯齿
        mPaint!!.color = Color.GREEN;
        setPaintStyle(Paint.Style.FILL);  //填充式
    }
    /**
     * 波纹半径率
     * @param maxRadiusRate
     */
    fun setMaxRadiusRate(maxRadiusRate: Float) {
        mMaxRadiusRate = maxRadiusRate
    }
    /**
     * 画笔颜色
     * @param color
     */
    fun setColor(color: Int) {
        mPaint!!.color = color
    }
    /**
     * 初始半径
     * @param radius
     */
    fun setInitialRadius(radius: Float) {
        mInitialRadius = radius
    }
    /**
     * 设置波纹持续时间
     * @param duration
     */
    fun setDuration(duration: Long) {
        mDuration = duration
    }
    /**
     * 最大波纹半径
     * @param maxRadius
     */
    fun setMaxRadius(maxRadius: Float) {
        mMaxRadius = maxRadius
        mMaxRadiusSet = true
    }
    /**
     * 波纹创建速度
     * @param speed
     */
    fun setSpeed(speed: Int) {
        mSpeed = speed
    }
    /**
     * 插值器,达到不同的效果
     * @param interpolator
     */
    fun setInterpolator(interpolator: Interpolator) {
        mInterpolator = interpolator
        if (mInterpolator == null) {
            mInterpolator = LinearInterpolator()
        }
    }
    /**
     * 提供给外界 设置画笔风格
     * @param style
     */
    fun setPaintStyle(style: Paint.Style?) {
        mPaint!!.style = style
    }
    /**
     * 提供给外界开来是整个过程
     */
    fun start() {
        if (!mIsRunning) {
            mIsRunning = true
            mCreateCircle.run() //开线程
        }
    }
    /**
     * 停止
     */
    fun stop() {
        mIsRunning = false
    }
    private val mCreateCircle: Runnable = object : Runnable {
        override fun run() {
            if (mIsRunning) {
                newCircle()
                postDelayed(this, mSpeed.toLong()) // 每隔mSpeed毫秒创建一个圆
            }
        }
    }
    /**
     * 创建圆
     */
    private fun newCircle() {
        val currentTime = System.currentTimeMillis()
        if (currentTime - mLastCreateTime < mSpeed) {
            return
        }
        val circle = Circle()
        mCircleList.add(circle)
        invalidate() //重新调用onDraw绘制
        mLastCreateTime = currentTime
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        if (!mMaxRadiusSet) {
            mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f
        }
    }
    override fun onDraw(canvas: Canvas) {
        val iterator = mCircleList.iterator() //得带期遍历
        while (iterator.hasNext()) { //是否=还有元素
            val circle = iterator.next() //拿到下一个
            if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
                mPaint!!.alpha = circle.getAlpha() //设置透明度
                canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), circle.getCurrentRadius(), mPaint!!) //设置半径
            } else {  //如果创建的时间大于最大  则移除
                iterator.remove()
            }
        }
        if (mCircleList.size > 0) {
            postInvalidateDelayed(10) //10毫秒刷新  快速给人错觉是动态的  其实是静态的很多圆
        }
    }
    /**
     * 绘制圆的类   getAlpha、getCurrentRadius插值器原因
     * 你可以在外部设置不同的插值器器,来实现波纹的不同动态效果;详情请学习插值器;
     * kotlin要想内部类访问外部类的成员变量 需要inner修饰
     */
    inner class Circle {
        val mCreateTime: Long //当前添加圆时间

        /**
         * 获得透明度  ↓0(消失)
         * getInterpolation传值越大,返回越大 因为是LinearInterpolator 传值返回一致
         *
         * @return
         */
        fun getAlpha(): Int {
            //当前时间处于总时间的百分比   当前时间/圆创建-消失总时间
            val percent: Float = ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration).toFloat()
            return ((1.0f - mInterpolator.getInterpolation(percent)) * 255).toInt()
        }

        /**
         * 获得当前的半径
         */
        fun getCurrentRadius(): Float {
            val percent: Float = ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration).toFloat()
            //最小半径+当前扩大百分比半径
            return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius)
        }

        init {
            mCreateTime = System.currentTimeMillis()
        }
    }
}

😜WaveOvalView-椭圆

椭圆的绘制和圆的绘制仅仅差在onDraw中,其他的都一样。onDraw使用canvas.drawOval即可。

Java版

/**
 *
 * @author akitaka
 * @filename WaveOvalViewJava
 * @describe 椭圆形的水波纹,而且椭圆的扁平方向也需要控制;;后期可考虑封装,继承WaveViewJava或者整体
 * @email 960576866@qq.com
 */
public class WaveOvalViewJava extends View {
    private long mDuration = 2000; // 一个波纹从创建到消失的持续时间
    /**
     * 插值器属性,可理解为指定动画如何变化的动动;有多种
     * LinearInterpolator--画从开始到结束,变化率是线性变化
     */
    private Interpolator mInterpolator = new LinearInterpolator();
    private float mInitialRadius;   // 初始波纹半径
    private float mMaxRadius;   // 最大波纹半径
    private Paint mPaint;
    private List<Circle> mCircleList = new ArrayList<>();//当前正在显示的圆集合
    private boolean mIsRunning;//绘制线程是否开始
    private int mSpeed = 500;   // 波纹的创建速度,每500ms创建一个
    private long mLastCreateTime;   //上一个创建圆的时间
    private boolean mMaxRadiusSet;   //如果设置了最大半径
    private float mMaxRadiusRate = 0.85f;   // 如果没有设置mMaxRadius,可mMaxRadius = 最小长度 * mMaxRadiusRate;

    public WaveOvalViewJava(Context context) {
        super(context);
    }
    public WaveOvalViewJava (Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  //抗锯齿
        setPaintStyle(Paint.Style.FILL);  //填充式
    }
    /**
     * 波纹半径率
     * @param maxRadiusRate
     */
    public void setMaxRadiusRate(float maxRadiusRate) {
        this.mMaxRadiusRate = maxRadiusRate;
    }
    /**
     * 画笔颜色
     * @param color
     */
    public void setColor(int color) {
        mPaint.setColor(color);
    }
    /**
     * 初始半径
     * @param radius
     */
    public void setInitialRadius(float radius) {
        mInitialRadius = radius;
    }
    /**
     * 设置波纹持续时间
     * @param duration
     */
    public void setDuration(long duration) {
        this.mDuration = duration;
    }
    /**
     * 最大波纹半径
     * @param maxRadius
     */
    public void setMaxRadius(float maxRadius) {
        this.mMaxRadius = maxRadius;
        mMaxRadiusSet = true;
    }
    /**
     * 波纹创建速度
     * @param speed
     */
    public void setSpeed(int speed) {
        mSpeed = speed;
    }
    /**
     * 插值器,达到不同的效果
     * @param interpolator
     */
    public void setInterpolator(Interpolator interpolator) {
        mInterpolator = interpolator;
        if (mInterpolator == null) {
            mInterpolator = new LinearInterpolator();
        }
    }
    /**
     * 提供给外界 设置画笔风格
     * @param style
     */
    public void setPaintStyle(Paint.Style style) {
        mPaint.setStyle(style);
    }
    /**
     * 提供给外界开来是整个过程
     */
    public void start() {
        if (!mIsRunning) {
            mIsRunning = true;
            mCreateCircle.run(); //开线程
        }
    }
    /**
     * 停止
     */
    public void stop() {
        mIsRunning = false;
    }
    private Runnable mCreateCircle = new Runnable() {
        @Override
        public void run() {
            if (mIsRunning) {
                newCircle();
                postDelayed(mCreateCircle, mSpeed); // 每隔mSpeed毫秒创建一个圆
            }
        }
    };
    /**
     * 创建圆
     */
    private void newCircle() {
        long currentTime = System.currentTimeMillis();
        if (currentTime - mLastCreateTime < mSpeed) {
            return;
        }
        Circle circle = new Circle();
        mCircleList.add(circle);
        invalidate();   //重新调用onDraw绘制
        mLastCreateTime = currentTime;
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (!mMaxRadiusSet) {
            mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f;
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        Iterator<Circle> iterator = mCircleList.iterator();   //得带期遍历
        while (iterator.hasNext()) { //是否=还有元素
            Circle circle = iterator.next();//拿到下一个
            if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
                mPaint.setAlpha(circle.getAlpha());  //设置透明度
//                canvas.drawCircle(getWidth() / 2, getHeight() / 2, circle.getCurrentRadius(), mPaint);  //设置半径来控制为椭圆
                RectF ovalRect = new RectF();
                //椭圆的绘制封装 需要更精细的考虑, left,top小于 right,bottom;;
                ovalRect.left = getWidth() / 2 - circle.getCurrentRadius();
                ovalRect.top = getWidth() / 2 - 1.5f * circle.getCurrentRadius();
                ovalRect.right = getWidth() / 2 + circle.getCurrentRadius();
                ovalRect.bottom = getWidth() / 2 + 1.5f * circle.getCurrentRadius();
                canvas.drawOval(ovalRect, mPaint);
                //需要API 21
//                canvas.drawOval(circle.getCurrentRadius(),circle.getCurrentRadius()-10,circle.getCurrentRadius(),circle.getCurrentRadius()-10,mPaint);
            } else {  //如果创建的时间大于最大  则移除
                iterator.remove();
            }
        }
        if (mCircleList.size() > 0) {
            postInvalidateDelayed(10);  //10毫秒刷新  快速给人错觉是动态的  其实是静态的很多圆
        }
    }
    /**
     * 绘制圆的类   getAlpha、getCurrentRadius插值器原因
     * 你可以在外部设置不同的插值器器,来实现波纹的不同动态效果;详情请学习插值器;
     */
    private class Circle {
        private long mCreateTime;  //当前添加圆时间
        public Circle() {
            this.mCreateTime = System.currentTimeMillis();
        }
        /**
         * 获得透明度  ↓0(消失)
         * getInterpolation传值越大,返回越大 因为是LinearInterpolator 传值返回一致
         * @return
         */
        public int getAlpha() {
            //当前时间处于总时间的百分比   当前时间/圆创建-消失总时间
            float percent = (float) ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration);
            return (int) ((1.0f - mInterpolator.getInterpolation(percent)) * 255);
        }
        /**
         * 获得当前的半径
         */
        public float getCurrentRadius() {
            float percent = (float) ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration);
            //最小半径+当前扩大百分比半径
            return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius);
        }

    }
}

Kotlin版

/**
 * Created by akitaka on 2022-06-23.
 * @author akitaka
 * @filename WaveOvalViewKotlin
 * @describe
 * @email 960576866@qq.com
 */
class WaveOvalViewKotlin : View {
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    var mDuration: Long = 2000 // 一个波纹从创建到消失的持续时间
    /**
     * 插值器属性,可理解为指定动画如何变化的动动;有多种
     * LinearInterpolator--画从开始到结束,变化率是线性变化
     */
    var mInterpolator: Interpolator = LinearInterpolator()
    var mInitialRadius = 0f// 初始波纹半径
    var mMaxRadius = 0f// 最大波纹半径
    var mPaint: Paint? = null
    var mCircleList: MutableList<Circle> = ArrayList() //当前正在显示的圆集合
    var mIsRunning = false//绘制线程是否开始
    var mSpeed = 500 // 波纹的创建速度,每500ms创建一个
    var mLastCreateTime: Long = 0//上一个创建圆的时间
    var mMaxRadiusSet = false//如果设置了最大半径
    var mMaxRadiusRate = 0.85f // 如果没有设置mMaxRadius,可mMaxRadius = 最小长度 * mMaxRadiusRate;
    init {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG);  //抗锯齿
        mPaint!!.color = Color.GREEN;
        setPaintStyle(Paint.Style.FILL);  //填充式
    }
    /**
     * 波纹半径率
     * @param maxRadiusRate
     */
    fun setMaxRadiusRate(maxRadiusRate: Float) {
        mMaxRadiusRate = maxRadiusRate
    }
    /**
     * 画笔颜色
     * @param color
     */
    fun setColor(color: Int) {
        mPaint!!.color = color
    }
    /**
     * 初始半径
     * @param radius
     */
    fun setInitialRadius(radius: Float) {
        mInitialRadius = radius
    }
    /**
     * 设置波纹持续时间
     * @param duration
     */
    fun setDuration(duration: Long) {
        mDuration = duration
    }

    /**
     * 最大波纹半径
     * @param maxRadius
     */
    fun setMaxRadius(maxRadius: Float) {
        mMaxRadius = maxRadius
        mMaxRadiusSet = true
    }
    /**
     * 波纹创建速度
     * @param speed
     */
    fun setSpeed(speed: Int) {
        mSpeed = speed
    }
    /**
     * 插值器,达到不同的效果
     * @param interpolator
     */
    fun setInterpolator(interpolator: Interpolator) {
        mInterpolator = interpolator
        if (mInterpolator == null) {
            mInterpolator = LinearInterpolator()
        }
    }
    /**
     * 提供给外界 设置画笔风格
     *
     * @param style
     */
    fun setPaintStyle(style: Paint.Style?) {
        mPaint!!.style = style
    }
    /**
     * 提供给外界开来是整个过程
     */
    fun start() {
        if (!mIsRunning) {
            mIsRunning = true
            mCreateCircle.run() //开线程
        }
    }
    /**
     * 停止
     */
    fun stop() {
        mIsRunning = false
    }
    private val mCreateCircle: Runnable = object : Runnable {
        override fun run() {
            if (mIsRunning) {
                newCircle()
                postDelayed(this, mSpeed.toLong()) // 每隔mSpeed毫秒创建一个圆
            }
        }
    }
    /**
     * 创建圆
     */
    private fun newCircle() {
        val currentTime = System.currentTimeMillis()
        if (currentTime - mLastCreateTime < mSpeed) {
            return
        }
        val circle = Circle()
        mCircleList.add(circle)
        invalidate() //重新调用onDraw绘制
        mLastCreateTime = currentTime
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        if (!mMaxRadiusSet) {
            mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f
        }
    }
    override fun onDraw(canvas: Canvas) {
        val iterator: MutableIterator<Circle> = mCircleList.iterator() //得遍历
        while (iterator.hasNext()) { //是否=还有元素
            val circle = iterator.next() //拿到下一个
            if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
                mPaint!!.alpha = circle.getAlpha() //设置透明度
                //                canvas.drawCircle(getWidth() / 2, getHeight() / 2, circle.getCurrentRadius(), mPaint);  //设置半径来控制为椭圆
                val ovalRect = RectF()
                //椭圆的绘制封装 需要更精细的考虑, left,top小于 right,bottom;;
                ovalRect.left = width / 2 - circle.getCurrentRadius()
                ovalRect.top = width / 2 - 1.5f * circle.getCurrentRadius()
                ovalRect.right = width / 2 + circle.getCurrentRadius()
                ovalRect.bottom = width / 2 + 1.5f * circle.getCurrentRadius()
                canvas.drawOval(ovalRect, mPaint)
                //需要API 21
//                canvas.drawOval(circle.getCurrentRadius(),circle.getCurrentRadius()-10,circle.getCurrentRadius(),circle.getCurrentRadius()-10,mPaint);
            } else {  //如果创建的时间大于最大  则移除
                iterator.remove()
            }
        }
        if (mCircleList.size > 0) {
            postInvalidateDelayed(10) //10毫秒刷新  快速给人错觉是动态的  其实是静态的很多圆
        }
    }

    /**
     * 绘制圆的类   getAlpha、getCurrentRadius插值器原因
     * 你可以在外部设置不同的插值器器,来实现波纹的不同动态效果;详情请学习插值器;
     * kotlin要想内部类访问外部类的成员变量 需要inner修饰
     */
    inner class Circle {
        val mCreateTime: Long //当前添加圆时间

        /**
         * 获得透明度  ↓0(消失)
         * getInterpolation传值越大,返回越大 因为是LinearInterpolator 传值返回一致
         *
         * @return
         */
        fun getAlpha(): Int {
            //当前时间处于总时间的百分比   当前时间/圆创建-消失总时间
            val percent: Float = ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration).toFloat()
            return ((1.0f - mInterpolator.getInterpolation(percent)) * 255).toInt()
        }

        /**
         * 获得当前的半径
         */
        fun getCurrentRadius(): Float {
            val percent: Float = ((System.currentTimeMillis() - mCreateTime) * 1.0 / mDuration).toFloat()
            //最小半径+当前扩大百分比半径
            return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius)
        }

        init {
            mCreateTime = System.currentTimeMillis()
        }
    }
}

📢作者:小空和小芝中的小空

📢转载说明-务必注明来源:芝麻粒儿 的个人主页 - 专栏 - 掘金 (juejin.cn)

📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。