使用 Jetpack Compose 让 SurfaceView 可任意滚动
什么是 Jetpack Compose?
Jetpack Compose 是用于构建原生 Android 界面的新工具包。
它可简化并加快 Android 上的界面开发,使用更少的代码、强大的工具和直观的 Kotlin API,快速让应用生动而精彩。
SurfaceView 使用之前滑动方法的缺陷
在 ‘解决 SurfaceView 的滑动问题(1)上下滑动’ 一文中我们讲过如何解决 SurfaceView 的上下滑动
但还是有很多问题,例如重复绘制内容,计算滑动等等是很耗时、耗性能的,如此便有了本文
SurfaceView 滑动问题的解决
请确保有 Jetpack Compose & Kotlin 协程 & ViewModel ~ LiveData 的依赖
1.继承 SurfaceView ,名称改为 CoroutineSurfaceInternal 并改为以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| class CoroutineSurfaceInternal @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : SurfaceView(context, attrs) {
private var lastJob: Job? = null
private var background = 0
init { setZOrderOnTop(true) setZOrderMediaOverlay(true) holder.setFormat(PixelFormat.TRANSPARENT) }
fun setSurfaceBackground(background: Int) { this.background = background }
@Suppress("ControlFlowWithEmptyBody") fun onSurfaceDraw(drawScope: Canvas.(CoroutineScope) -> Unit) { lastJob?.cancel() lastJob = CoroutineScope(Dispatchers.IO).launch { while (!holder.surface.isValid) { if (!isActive) { return@launch } } synchronized(holder) { val canvas = holder.lockCanvas() canvas.drawColor(background) drawScope.invoke(canvas, this) holder.unlockCanvasAndPost(canvas) } } }
}
|
CoroutineSurfaceInternal 是 SurfaceView 使用协程的内部原生类 ,后面会在 Compose 中进行包装
接下来用 Jetpack Compose 对 CoroutineSurfaceInternal 进行包装 ,创建 CoroutineSurface.kt 并改为以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
@Suppress("UNUSED_EXPRESSION") @Composable fun CoroutineSurface(modifier: Modifier = Modifier, drawScope: Canvas.(CoroutineScope) -> Unit) { val viewModel: CoroutineSurfaceViewModel = viewModel() val observableObject by viewModel.observableObject.observeAsState(0) AndroidView(factory = { CoroutineSurfaceInternal(it) }, modifier = modifier) { Log.e("StateChanged", observableObject.toString()) it.setSurfaceBackground(if (isDarkTheme.value) Color.BLACK else Color.WHITE) it.onSurfaceDraw(drawScope) } }
@Suppress("unused") fun ComponentActivity.invalidateCoroutineSurface() { val viewModel = ViewModelProvider(this).get(CoroutineSurfaceViewModel::class.java) viewModel.onObservableObjectChanged() }
|
最后我们只需要指定让 Column 可滑动即可
1 2 3 4 5 6 7 8 9 10 11 12 13
|
Column( Modifier .verticalScroll(rememberScrollState()) .horizontalScroll(rememberScrollState()) ) { CoroutineSurface(modifier = Modifier.size(2000.dp)) { } }
|
最后在你自己的 Jetpack Compose Activity 中使用这个 Column
需要刷新界面调用 invalidateCoroutineSurface 主动刷新即可