android小动画:不断扩散的圆点

 效果图

(ps: 其实就两个半径和透明度一起变化的小圆, 本项目中用来指示指尖位置)

实现原理

监听点击的位置,在父布局中动态增加 自定义的动画View

代码实现

(1)activity点击监听及添加View

   // 触屏点击位置
    private var pointX: Int = 0
    private var pointY: Int = 0
    private var circleView: SpreadCircleView?= null

    // 触摸点击
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event!!.action) {
            MotionEvent.ACTION_DOWN -> {
                pointX = event.x.toInt()
                pointY = event.y.toInt()
            }
            MotionEvent.ACTION_MOVE -> { }
            MotionEvent.ACTION_UP ->{ addPointCircle() }
            else -> { }
        }
        return true
    }
   /**
     * 添加自动扩散的圆点 View
     */
    fun addPointCircle(){
        if(circleView == null){
            circleView = SpreadCircleView(this);
            circleView?.let{
                lifecycle.addObserver(it)
            }
        }
        binding.rootLayout.removeView(circleView)
        circleView?.let{
            // 宽度和高度相同
            val width = it.maxRadius.toInt() * 2
            var lp = FrameLayout.LayoutParams(width,  width )
            lp.marginStart = pointX - width/2
            lp.topMargin = pointY - width/2
            binding.rootLayout.addView(it, lp)
            it.startAnimation()
        }
    }

(2)圆点View实现(属性动画,根据动画进度来确定圆的当前半径,利用LifecycleObserver绑定周期)

/**
 *  Created by Liming on  2021/9/1 15:36
 *  不断扩散的小圆, 用于显示指尖位置
 */
class SpreadCircleView : View, LifecycleObserver {

    private var paint: Paint = Paint()
    // 圆圈最大半径
    val maxRadius = 25.toPx()
    // 圆圈中心点
    var centerX:Int = 0
    var centerY:Int = 0

    private var animator : ObjectAnimator? = null

    // 是否已开始绘制第二个圆
    var hasDrawCicle2 = false

    // 动画进度
    private var progress = 0f
        set(value){
            field = value
            // 刷新界面
            invalidate()
        }

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context,
        attrs,
        defStyleAttr)

    init{
        paint.style = Paint.Style.FILL
        paint.color = ContextCompat.getColor(context, R.color.rect_orange) // #ffa200
        paint.strokeWidth = 3.toPx()
        paint.isAntiAlias = true // 防锯齿
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //圆心位置
        centerX = w / 2;
        centerY = h / 2;
    }

    override fun draw(canvas: Canvas?) {
        super.draw(canvas)
        // 第一个圆
        drawCircle(canvas, progress)
        // 第二个圆
        if(hasDrawCicle2 || progress > 0.5f ){
            // 第一个圆的进度第一次达到 0.5 时,开始绘制第二个圆,
            hasDrawCicle2 = true
            var progress2 = progress + 0.5f
            if(progress2 > 1){
                progress2 = progress2 - 1
            }
            drawCircle(canvas, progress2)
        }
    }

    /**
     * 根据进度绘制 半径和透明度变化的圆
     */
    fun drawCircle(canvas: Canvas?, animProgress: Float){
        // 透明度 0 - 255
        var alpha = 255 * (1 - animProgress)
        paint.alpha = alpha.toInt()
        var radius = maxRadius * animProgress
        // 绘制圆
        canvas?.drawCircle(centerX.toFloat(), centerY.toFloat(), radius, paint )
    }

    private fun getAnimator(): ObjectAnimator?{
        if(animator == null){
            animator = ObjectAnimator.ofFloat(this,
                "progress", 0f, 0.99f)
            animator?.duration = 1500
            animator?.repeatCount = -1 //-1代表无限循环
            animator?.interpolator = LinearInterpolator()
        }
        return animator
    }

    fun startAnimation() {
        // 开始动画
        getAnimator()?.start()
        hasDrawCicle2 = false
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun resume() {
        // 开始动画
        animator?.start()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun pause() {
        animator?.pause()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destory() {
        // 清除动画,避免内存泄漏,
        animator?.cancel()
        clearAnimation()
    }
} 

补充一个用到的扩展函数

    fun Int.toPx(): Float{
        val resources = Resources.getSystem()
        return TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                this.toFloat(),
                resources.displayMetrics
        )
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义圆点指示器

    本文实例为大家分享了Android自定义圆点指示器的具体代码,供大家参考,具体内容如下 先上效果图 大概思路就是自定义View 从左至右绘制圆点 然后在ViewPager的OnPageChangeListener中设置当前页面的圆点 下面是代码 先定义属性 <resources> <attr name="selectedColor" format="color"/> <attr name="unselectedColor&qu

  • Android 滑动小圆点ViewPager的两种设置方法详解流程

    第一种方法: 一.测试如下,直接设置小圆点不是图标 二.准备工作 1.在drawable创建dot.xml,设置小圆点,比较方便 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="t

  • Android实现两圆点之间来回移动加载进度

    本文实例为大家分享了Android实现两圆点之间来回移动加载进度的具体代码,供大家参考,具体内容如下 一.前言 最近喜欢上自定义控件,喜欢实现一些简约有趣的控件,也好巩固下以前学得知识和不断的学习新知识,程序员嘛,活到老学到老. 这篇文章接着上一篇文章:Android_自定义控件之水平圆点加载进度条,类似的实现方式,都是些比较简单的view绘制. 二.实现 先看下实现的效果吧: 说下实现思路:圆点x轴会有个位移变化量,当位移达到圆点直径+圆点间距之和就回改变方向(改变方向就是通过变化量值不断增加

  • android仿直播圆点加载效果

    今天实现一个很多app中使用到的加载进度条的效果,可能我们平时数据加载都使用到的是系统自带的,但是也有很多app加载进度条的效果实现挺好看,就是三个点不停的水平跑而且是变换颜色的,其实这个效果很简单, 分析: 第一步: 第二步: 为了圆的颜色 大小,以及移动的距离都对外开放,采用了自定义属性的方式,当然也可以进行设置, 分析了后 代码就直接上了, <?xml version="1.0" encoding="utf-8"?> <resources&g

  • android小动画:不断扩散的圆点

     效果图 (ps: 其实就两个半径和透明度一起变化的小圆, 本项目中用来指示指尖位置) 实现原理 监听点击的位置,在父布局中动态增加 自定义的动画View 代码实现 (1)activity点击监听及添加View // 触屏点击位置 private var pointX: Int = 0 private var pointY: Int = 0 private var circleView: SpreadCircleView?= null // 触摸点击 override fun onTouchEv

  • Android实现水波纹扩散效果

    本文实例为大家分享了Android实现水波纹扩散效果的具体代码,供大家参考,具体内容如下 先上图 囧!没有图片所以就拿了小安代替了. 先看一下如何使用这个View. <jianpan.com.mybutton.view.RippleDiffuse android:layout_width="200dp" android:layout_height="200dp" app:btn_img_res="@drawable/rd" app:ripp

  • Android 帧动画的实例详解

    Android 帧动画的实例详解 对于 Android 帧动画 大体上可以理解成 一张张图片 按一定顺序切换, 这样当连续几张图是一组动画时,就可以连起来了看成是一个小电影,你懂得 好得,比就装到这里,下面开始进入正题,由于产品需求 需要做一个 声音喇叭动态切换的样式,我特么第一就想到是帧动画切换,然后就百度了一些资料,发现 真的, 现在这个网上太多的资料是 copy粘贴过来的, 一错全错,对于这种情况我只想说,made,一群垃圾, 所以今天我将带你们走进Android 正确帧动画地址. 第一步

  • Android实现水波纹扩散效果的实例代码

    本文讲述了Android实现水波纹扩散效果的实例代码.分享给大家供大家参考,具体如下: 项目地址下载 1.效果图: 2.使用方法: 在xml里使用RippleImageView自定义控件: xmlns:app="http://schemas.android.com/apk/res-auto" <com.army.rippleimage.RippleImageView android:id="@+id/rippleImageView" android:layou

  • Android实现动画效果详解

    目前Android平台提供了两类动画一类是Tween动画,第二类就是 Frame动画,具体内容介绍请看下文: 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转.平移.放缩和渐变). 第二类就是 Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似. 实现动画有两种方式:一种使用XML文件(文件放在res/anim),一种直接代码搞定  1.透明度控制动画效果alpha <!-- 透明度控制动画效果alpha 浮点型值: fromAlpha 动画起始时透明

  • Android 属性动画ValueAnimator与插值器详解

    Android 属性动画ValueAnimator与插值器详解 一.ValueAnimator详解: ValueAnimator是整个动画的核心,ObjectAnimator即是继承自ValueAnimator来实现. ValueAnimator更像是一个数值发生器,用来产生具有一定规律的数字,从而让调动者来控制动画的实现过程. 1.ValueAnimator的使用: ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); val

  • Android精灵动画用法实例

    本文实例讲述了Android精灵动画用法.分享给大家供大家参考.具体如下: ElaineAnimated.java文件如下: package net.obviam.walking.model; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; public class ElaineAnimated

  • Android 混合动画详解及实现代码

    Android 混合动画 在Android开发,我们会经常使用到动画,但是简单的一种动画(如旋转.缩放.渐变.位移等)有时候并不能满足我们项目的要求,这时候就需要运用到混合动画,那么在安卓中是如何实现一个炫酷的混合动画,下面是一个混合动画实现的其中一个实现方式: 1.首先要在res目录下建立一个anim文件,在anim建立一个hybrid.xml文件如下: <?xml version="1.0" encoding="utf-8"?> <set xm

  • Android开场动画类完整实现代码

    本文所述实例为在android中开起开场动画类,已封装好,进行android开发的朋友可使用.在这个类中,你可以:设置开场动画的图片资源.返回下一个要启动的Activity.显示开场动画.执行耗时的操作.创建启动时的界面Layout.设置屏幕的方向.默认是竖屏.开场动画的图片资源类.封装了图片.播放时间.开始时的透明程度等. 具体实现代码如下: package com.lurencun.cfuture09.androidkit.ui; import java.io.Serializable; i

  • Android 吸入动画效果实现分解

    Android 吸入动画效果详解 .  这里,我要介绍的是如何在Android上面实现一个类似的效果.先看看我实现的效果图.  上图演示了动画的某几帧,其中从1 - 4,演示了图片从原始图形吸入到一个点(红色标识). 实现这样的效果,我们利用了Canvas.drawBitmapMesh()方法,这里涉及到了一个Mesh的概念. 2,Mesh的概念 Mesh表示网格,说得通俗一点,可以将画板想像成一张格子布,在这个张布上绘制图片.对于一个网格端点均匀分布的网格来说,横向有meshWidth + 1

随机推荐