1. 自定义View, 测试耗时绘制卡顿, MyView.kt
class MyView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val mTag = "MyTag"
private var centerX = 0f
private var centerY = 0f
private var colors =
arrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.GRAY)
private val paint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 5f
}
// 一秒刷新60帧 60HZ 16毫秒保证执行完draw方法,不会觉得卡顿
override fun draw(canvas: Canvas?) {
super.draw(canvas)
repeat(3000) {
paint.color = colors.random()
canvas?.drawCircle(centerX, centerY, it.toFloat() / 5, paint)
}
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
centerX = event?.x ?: 0f
centerY = event?.y ?: 0f
invalidate()
return super.onTouchEvent(event)
}
}
2. 自定义SurfaceView,测试耗时绘制,不影响主线程,MySurfaceView.kt
class MySurfaceView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : SurfaceView(context, attrs) {
private val mTag = "MyTag"
private var centerX = 0f
private var centerY = 0f
private var colors =
arrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.GRAY)
private val paint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 5f
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
centerX = event?.x ?: 0f
centerY = event?.y ?: 0f
val canvas = holder.lockCanvas()
canvas.drawColor(Color.BLACK)
repeat(3000) {
paint.color = colors.random()
canvas.drawCircle(centerX, centerY, it.toFloat() / 5, paint)
}
holder.unlockCanvasAndPost(canvas)
return super.onTouchEvent(event)
}
}
3. 绘制水波纹动效,BubbleSurfaceView.kt
class BubbleSurfaceView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : SurfaceView(context, attrs) {
private var colors =
arrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.GRAY)
private val paint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 5f
//离散路径效果 segmentLength:片段的长度 deviation:波动的程度
//pathEffect = DiscretePathEffect(30f, 20f)
pathEffect = ComposePathEffect(CornerPathEffect(30f), DiscretePathEffect(30f, 20f))
}
private data class Bubble(val x: Float, val y: Float, val color: Int, var radius: Float)
private val bubblesList = mutableListOf<Bubble>()
override fun onTouchEvent(event: MotionEvent?): Boolean {
val x = event?.x ?: 0f
val y = event?.y ?: 0f
val color = colors.random()
val bubble = Bubble(x, y, color, 1f)
bubblesList.add(bubble)
if (bubblesList.size > 30) bubblesList.removeAt(0)
return super.onTouchEvent(event)
}
init {
CoroutineScope(Dispatchers.Default).launch {
while (true) {
if (holder.surface.isValid) {
val canvas = holder.lockCanvas()
//重置Canvas
canvas.drawColor(Color.BLACK)
//toList: 在副本上操作,保证同一时刻不操作同一个list,否则会报错
//filter: 过滤小于1000的才执行
bubblesList.toList().filter { it.radius < 3000 }.forEach {
paint.color = it.color
canvas.drawCircle(it.x, it.y, it.radius, paint)
it.radius += 10f
}
holder.unlockCanvasAndPost(canvas)
}
}
}
}
}
4. 布局文件引用自定义View, activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.surfaceview.BubbleSurfaceView
android:id="@+id/view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:visibility="invisible"
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="91dp"
android:layout_height="85dp"
android:layout_marginTop="64dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/view" />
</androidx.constraintlayout.widget.ConstraintLayout>
5. 调用布局文件 MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
6. 效果图