美文网首页JetPack
JetPack Compose 对Compose组件进行截图

JetPack Compose 对Compose组件进行截图

作者: 进击的小大叔 | 来源:发表于2022-09-09 12:34 被阅读0次

    开门见山,直接上码

    package com.satis.compose.get.widget
    
    import android.graphics.Bitmap
    import android.graphics.Canvas
    import android.view.View
    import android.view.ViewGroup
    import android.view.ViewTreeObserver
    import android.widget.FrameLayout
    import androidx.compose.material.Surface
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.MutableState
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.remember
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.geometry.Rect
    import androidx.compose.ui.layout.boundsInRoot
    import androidx.compose.ui.layout.onGloballyPositioned
    import androidx.compose.ui.platform.ComposeView
    import androidx.compose.ui.viewinterop.AndroidView
    
    /**
    * @author sunshaobei on 2022/9/9
    * Compose 对包裹控件截图
    */
    
    data class CaptureState(
      val capture: Boolean = false
    )
    
    fun MutableState<CaptureState>.capture() {
      this.value = this.value.copy(capture = true)
    }
    
    private fun MutableState<CaptureState>.captureComplete() {
      this.value = this.value.copy(capture = false)
    }
    
    @Composable
    fun rememberCaptureController(): MutableState<CaptureState> {
      return remember {
          mutableStateOf(CaptureState(capture = false))
      }
    }
    
    @Composable
    fun ComposeCapture(
      captureController: MutableState<CaptureState> = rememberCaptureController(),
      onSaveBitmap: (Bitmap?) -> Unit,
      content: @Composable () -> Unit
    ) {
      var bounds = remember {
          mutableStateOf<Rect?>(null)
      }
      //依据状态值 选择是否使用AndroidView进行展示获取截图
      if (captureController.value.capture) {
          CaptureView(captureController = captureController, onSaveBitmap = onSaveBitmap,bounds = bounds,content = content)
      } else {
          Surface(modifier = Modifier.onGloballyPositioned {
              bounds.value = it.boundsInRoot()
          },content = content)
    
      }
    }
    
    @Composable
    private fun CaptureView(
      captureController: MutableState<CaptureState>,
      bounds: MutableState<Rect?>,
      onSaveBitmap: ((Bitmap?) -> Unit)? = null,
      content: @Composable () -> Unit
    ) {
      AndroidView(factory = {
          FrameLayout(it).apply {
              layoutParams = ViewGroup.LayoutParams(
                  (bounds.value!!.right - bounds.value!!.left).toInt(),
                  (bounds.value!!.bottom - bounds.value!!.top).toInt()
              )
              val composeView = ComposeView(it).apply {
                  setContent {
                      content()
                  }
              }
              drawListener(composeView,this,captureController,onSaveBitmap)
              addView(
                  composeView, ViewGroup.LayoutParams(
                      ViewGroup.LayoutParams.MATCH_PARENT,
                      ViewGroup.LayoutParams.MATCH_PARENT
                  )
              )
    
          }
      })
    }
    
    private fun drawListener(
      composeView: View, viewGroup: ViewGroup,
      captureController: MutableState<CaptureState>,
      onSaveBitmap: ((Bitmap?) -> Unit)? = null,
    ) {
      val drawListener = object : ViewTreeObserver.OnDrawListener {
          var remove = false
          override fun onDraw() {
              if (composeView.width > 0) {
                  if (!remove) {
                      // View 绘制第一帧 开始截图并移除 监听,随后切换截图状态 回到Compose组件
                      remove = true
                      composeView.post {
                          val bitmap = getViewGroupBitmap(viewGroup)
                          // 切换状态 回到Compose
                          captureController.captureComplete()
                          onSaveBitmap?.invoke(bitmap)
                          composeView.viewTreeObserver.removeOnDrawListener(this)
                      }
                  }
    
              }
          }
      }
      composeView.viewTreeObserver.addOnDrawListener(drawListener)
    }
    
    /**
    * @param viewGroup viewGroup
    * @return Bitmap
    */
    private fun getViewGroupBitmap(viewGroup: ViewGroup): Bitmap? {
      val bitmap = Bitmap.createBitmap(viewGroup.width, viewGroup.height, Bitmap.Config.ARGB_8888)
      val canvas = Canvas(bitmap)
      viewGroup.draw(canvas)
      return bitmap
    }
    
    

    由于官方并没有提供在Compose中截图的方式,所以改变了下思路,由状态切换为 AndroidView进行截图,截图后切换回Compose展示

    具体使用如下

    @Compose
    fun testCaptur(){
            //截图控制器
            val captureController = rememberCaptureController()
           Column(horizontalAlignment = Alignment.CenterHorizontally) {
                 ComposeCapture(
                       captureController = captureController,
                       onSaveBitmap = {
                              //Todo 返回截图的 bitmap
                       }) {
                                Column(
                                       horizontalAlignment = Alignment.CenterHorizontally
                                ) {
                                    Image(
                                         painter = painterResource(id = R.drawable.wechat),
                                          contentDescription = null
                                    )
                                   Text(text = "测试截图bitmap")
                                   Text(text = "测试截图bitmap")
                                   Text(text = "测试截图bitmap")
                                   Text(text = "测试截图bitmap")
                         }
               }
               Button(
                      onClick = { 
                            //触发截图
                            captureController.capture()
                        }
                ) {
                   Text(text = "save")
                 }
        }
    }
    
    

    相关文章

      网友评论

        本文标题:JetPack Compose 对Compose组件进行截图

        本文链接:https://www.haomeiwen.com/subject/aunanrtx.html