小动画— 不断扩散的圆点

小动画— 不断扩散的圆点

效果图

(ps: 其实就两个半径和透明度一起变化的小圆, 显示坐标位置为点击位置)
请添加图片描述

实现原理

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

代码实现(android、kotlin)

(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
        )
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安卓圆点呼吸动画可以使用属性动画实现,具体步骤如下: 1. 在布局文件中添加一个圆点视图: ```xml <View android:id="@+id/dot" android:layout_width="20dp" android:layout_height="20dp" android:layout_centerInParent="true" android:background="@drawable/dot_bg" /> ``` 其中 `@drawable/dot_bg` 是圆点的背景样式,可以自定义。 2. 在代码中使用属性动画实现圆点大小和透明度的变化: ```java // 获取圆点视图 View dotView = findViewById(R.id.dot); // 创建属性动画对象,设置动画属性为 scaleX、scaleY、alpha ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( dotView, PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.3f, 1.0f), PropertyValuesHolder.ofFloat("scaleY", 1.0f, 1.3f, 1.0f), PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0f) ); // 设置动画时长和重复次数 animator.setDuration(1500); animator.setRepeatCount(ValueAnimator.INFINITE); // 开始动画 animator.start(); ``` 3. 创建自定义的圆点背景样式 `dot_bg.xml`,实现圆点变大和透明度降低的效果: ```xml <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="20dp" android:height="20dp" /> <solid android:color="@color/colorAccent" /> <alpha android:fromAlpha="1.0" android:toAlpha="0.3" android:duration="1500" android:repeatCount="infinite" android:repeatMode="reverse" /> <scale android:fromXScale="1.0" android:toXScale="1.3" android:fromYScale="1.0" android:toYScale="1.3" android:pivotX="50%" android:pivotY="50%" android:duration="1500" android:repeatCount="infinite" android:repeatMode="reverse" /> </shape> ``` 其中 `alpha` 和 `scale` 标签分别实现了透明度和大小的变化效果,`duration` 表示动画时长,`repeatCount` 表示重复次数,`repeatMode` 表示重复模式。 运行程序即可看到圆点呼吸动画效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值