(Kotlin)Android 自定义蓝牙扫描动画:多波浪扩散效果

这是一个用于 Android 的自定义 View,模拟蓝牙扫描时的多波浪扩散动画效果。每个波浪的半径逐渐增大,透明度逐渐降低,形成连续的波纹扩散效果。通过调整动画的延迟时间和时长,确保波浪之间的间隙较小,动画流畅且美观。

主要特性:

多波浪扩散:

支持多个圆圈(波浪)依次扩散,形成连续的波纹效果。

每个圆圈的半径逐渐增大,透明度逐渐降低。

间隙较小:

通过调整动画的延迟时间和动画时长,确保波浪之间的间隙较小。

自定义View:

使用 Canvas 和 Paint 实现自定义绘制。

使用 ValueAnimator 实现平滑的动画效果。

适用场景:

蓝牙扫描界面。

雷达扫描效果。

其他需要波纹扩散动画的场景。

使用方法:

将 BluetoothScanView 添加到布局文件中。

在 Activity 中调用 startScan() 启动动画,调用 stopScan() 停止动画。

实现步骤
1. 自定义View
BluetoothScanView.kt

复制代码
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View

class BluetoothScanView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val scanPaint = Paint().apply {
        color = Color.BLUE
        style = Paint.Style.STROKE
        strokeWidth = 5f
        isAntiAlias = true
    }
    private val circles = mutableListOf<Circle>()
    private val animators = mutableListOf<ValueAnimator>()

    private fun init() {
        // 初始化圆圈和动画列表
        circles.clear()
        animators.clear()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val centerX = width / 2
        val centerY = height / 2

        // 绘制所有圆圈
        for (circle in circles) {
            scanPaint.alpha = circle.alpha
            canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), circle.radius.toFloat(), scanPaint)
        }
    }

    fun startScan() {
        if (animators.isNotEmpty()) return

        init()

        // 初始化3个圆圈
        repeat(3) { 
            circles.add(Circle(0, 255))
        }

        // 为每个圆圈创建独立的动画
        for ((i, circle) in circles.withIndex()) {
            val animator = ValueAnimator.ofFloat(0f, 1f).apply {
                duration = 1500
                startDelay = i * 500L
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.RESTART
                addUpdateListener {
                    val progress = animatedValue as Float
                    circle.radius = (progress * width / 2).toInt()
                    circle.alpha = (255 * (1 - progress)).toInt()
                    invalidate()
                }
            }
            animators.add(animator)
            animator.start()
        }
    }

    fun stopScan() {
        animators.forEach { it.cancel() }
        animators.clear()
        circles.clear()
        invalidate()
    }

    // 圆圈类,用于存储半径和透明度
    private data class Circle(var radius: Int, var alpha: Int)
}

注意:在Kotlin中,我们使用了@JvmOverloads注解来支持Java中的多构造函数特性。同时,通过使用apply、let、repeat等作用域函数简化了代码,并利用Kotlin的数据类(data class)特性定义了Circle类。此外,也对一些变量声明进行了调整,使其更符合Kotlin的习惯用法。

Activity代码:

复制代码
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var bluetoothScanView: BluetoothScanView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化自定义View
        bluetoothScanView = findViewById(R.id.bluetoothScanView)

        // 确保View尺寸已确定后启动动画
        bluetoothScanView.post {
            bluetoothScanView.startScan() // 启动扫描动画
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        bluetoothScanView.stopScan() // 停止扫描动画
    }
}

布局文件

复制代码
<?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:padding="16dp">

    <!-- 自定义蓝牙扫描View -->
    <com.example.BluetoothScanView
        android:id="@+id/bluetoothScanView"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true" />

</RelativeLayout>

运行效果
波浪扩散:

页面加载后,第一个圆圈开始扩散,随后第二个、第三个圆圈依次开始。

每个圆圈的半径逐渐增大,透明度逐渐降低。

间隙较小:

每个波浪之间的启动间隔为 500 毫秒,动画时长为 1500 毫秒,波浪之间的间隙较小。

连续波纹效果:

当一个圆圈的动画结束时,下一个圆圈的动画立即开始,形成连续的波纹效果。

动画循环:

动画无限循环,波纹效果持续不断。

相关推荐
懂点Tech2 小时前
ctfshow MISC入门图片篇(信息附加):misc41解题思路
开发语言·python
catchadmin2 小时前
PHP 8.7 协程新提案 让跨协程代码共享请求身份
开发语言·php
念何架构之路3 小时前
go-grpc设计思想
开发语言·后端·golang
吹什么轩4 小时前
MySQL:数据类型
android·adb
酷炫码神4 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript
Elastic 中国社区官方博客4 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1885 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
造火箭5 小时前
安卓不同类型自动化测试介绍
android
步行cgn5 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
传奇开心果编程6 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用