(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 毫秒,波浪之间的间隙较小。

连续波纹效果:

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

动画循环:

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

相关推荐
DICOM医学影像4 分钟前
2. go语言从零实现以太坊客户端-查询区块链账户余额
开发语言·golang·区块链·以太坊·web3.0·hardhat
王正南6 分钟前
安卓逆向之LSposed开发(一)
android·xposed·lsposed
Data_agent15 分钟前
Python 编程实战:函数与模块化编程及内置模块探索
开发语言·python
new_zhou15 分钟前
vs2019+qt工程中生成dump文件及调试
开发语言·qt·visual studio·dump调试
栈与堆40 分钟前
LeetCode 19 - 删除链表的倒数第N个节点
java·开发语言·数据结构·python·算法·leetcode·链表
一路向北·重庆分伦42 分钟前
03-01:MQ常见问题梳理
java·开发语言
txinyu的博客1 小时前
结合游戏场景理解,互斥锁,读写锁,自旋锁,CAS / 原子变量,分段锁
开发语言·c++·游戏
YIN_尹1 小时前
【MySQL】数据类型(上)
android·mysql·adb
阿里嘎多学长1 小时前
2026-01-11 GitHub 热点项目精选
开发语言·程序员·github·代码托管
yuanyikangkang1 小时前
STM32 lin控制盒
开发语言