【问题标题】:Using Zxing Library with Jetpack compose将 Zxing 库与 Jetpack 组合使用
【发布时间】:2022-04-12 17:50:19
【问题描述】:

我正在尝试使用 zxing 库实现 qr 扫描仪。为此,我在屏幕上添加了一个按钮,单击它,我将启动扫描仪,如下所示

Button(
        onClick = {
            val intentIntegrator = IntentIntegrator(context)
            intentIntegrator.setPrompt(QrScanLabel)
            intentIntegrator.setOrientationLocked(true)
            intentIntegrator.initiateScan()
        },
        modifier = Modifier
            .fillMaxWidth()
    ) {
        Text(
            text = QrScanLabel
        )
    }

但是,它启动了一个意图,期望 onActivityResult 方法返回结果。 Jetpack compose 使用rememberLauncherForActivityResult,如下所示

val intentLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartIntentSenderForResult()
    ) {
        if (it.resultCode != RESULT_OK) {
            return@rememberLauncherForActivityResult
        }
        ...
    }

但是我们如何在这里将两者整合在一起呢?

【问题讨论】:

    标签: zxing android-jetpack-compose


    【解决方案1】:

    我使用相同的库制作了一个临时解决方案: Gradle 依赖项:

    implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
    implementation 'com.google.zxing:core:3.4.0'
    

    我的新屏幕带有 jetpack compose 和相机捕捉功能,适用于我的应用:

    @Composable
    fun AdminClubMembershipScanScreen(navController: NavHostController) {
        val context = LocalContext.current
        var scanFlag by remember {
            mutableStateOf(false)
        }
    
        val compoundBarcodeView = remember {
            CompoundBarcodeView(context).apply {
                val capture = CaptureManager(context as Activity, this)
                capture.initializeFromIntent(context.intent, null)
                this.setStatusText("")
                capture.decode()
                this.decodeContinuous { result ->
                    if(scanFlag){
                        return@decodeContinuous
                    }
                    scanFlag = true
                    result.text?.let { barCodeOrQr->
                        //Do something and when you finish this something
                        //put scanFlag = false to scan another item
                        scanFlag = false
                    }
                    //If you don't put this scanFlag = false, it will never work again.
                    //you can put a delay over 2 seconds and then scanFlag = false to prevent multiple scanning 
                    
                }
            }
        }
    
        AndroidView(
            modifier = Modifier,
            factory = { compoundBarcodeView },
        )
    }
    

    【讨论】:

    • 感谢您的回答,它很有帮助。只是想问一下它是特定于条形码视图还是也可以用于二维码? @jose-pose-s
    • 嗨@bharat-kumar!是的,此代码适用于条形码和二维码。
    • 我使用了上面的代码,它的扫描很好,但即使在导航到新的撰写屏幕后,它仍然处于活动状态,并且如果相机面对一个扫描二维码。我该如何避免呢?
    • @bharat-kumar 您至少有 3 个选项: 1º 导航前转向 scanFlag = true 并防止在后台扫描,但如果您回来,相机已准备好。 2º 使用compoundBarcodeView .pause() 暂停相机,但要重新开始,您必须调用compoundBarcodeView .decodeContinuous { 这在函数式编程中会很复杂。 3º 选项更改导航系统,如果您不需要更多摄像头,请使用navController.navigate("route") -> route{ popUpTo(route){ saveState = true} launchSingleTop = true restoreState = true } 删除此屏幕并导航到您想要的目的地。
    • 嗨 @Mehdi.ncb 我编辑了我的代码,你应该使用 scanFlag = false 再次启用扫描,是一个防止多重扫描的标志,当然如果你把 always 设置为 false 将扫描相同的代码 múltiple时间,如果你不想,你可以扫描等待 10 秒,然后输入 scanFlag = false 例如。
    【解决方案2】:

    由于zxing-android-embedded:4.3.0 有一个ScanContract,可以直接从 Compose 中使用:

    val scanLauncher = rememberLauncherForActivityResult(
        contract = ScanContract(),
        onResult = { result -> Log.i(TAG, "scanned code: ${result.contents}") }
    )
    
    Button(onClick = { scanLauncher.launch(ScanOptions()) }) {
        Text(text = "Scan barcode")
    }
    

    【讨论】:

      【解决方案3】:

      我有一个问题,我的代码和你一样,但我不知道为什么它显示黑屏

      代码添加产品

      @ExperimentalPermissionsApi
      @Composable
      fun AddProduct(
          navController: NavController
      ) {
          val context = LocalContext.current
          var scanFlag by remember {
              mutableStateOf(false)
          }
      
          val compoundBarcodeView = remember {
              CompoundBarcodeView(context).apply {
                  val capture = CaptureManager(context as Activity, this)
                  capture.initializeFromIntent(context.intent, null)
                  this.setStatusText("")
                  capture.decode()
                  this.decodeContinuous { result ->
                      if(scanFlag){
                          return@decodeContinuous
                      }
                      scanFlag = true
                      result.text?.let { barCodeOrQr->
                          //Do something
      
                      }
                      scanFlag = false
                  }
              }
          }
      
          AndroidView(
              modifier = Modifier.fillMaxSize(),
              factory = { compoundBarcodeView },
          )
      
      }
      

      【讨论】:

      • 你可以检查应用是否有相机权限。
      • 是的,我有权限,我会把代码放在编辑中
      • 将此代码:- this.resume() 在 capture.decode() 之前或之后,并检查是否有帮助。
      • 它已经解决了我的问题,但现在我遇到了另一个问题,当我将相机放在代码前面时,应用程序正在多次扫描条形码
      • 嗨@Mehdi.ncb 我编辑我的代码,你应该使用scanFlag = false再次启用扫描,是一个防止多扫描的标志,当然如果你把always设置为false将扫描相同的代码多时间,如果你不想,你可以扫描等待 10 秒,然后输入scanFlag = false
      【解决方案4】:

      已接受答案的附录

      此答案深入探讨了@Bharat Kumar 和@Jose Pose S 评论的问题 在接受的答案中。

      我基本上只是在我的代码中实现了接受的答案,然后在定义 compundBarCodeView 之后添加了以下代码

      DisposableEffect(key1 = "someKey" ){
          compoundBarcodeView.resume()
          onDispose {
              compoundBarcodeView.pause()
          }
      }
      

      这可确保扫描仪仅在前台处于活动状态并释放我们的设备时才处于活动状态。

      TL;DR

      即使在您成功扫描 QR 码并离开扫描仪屏幕后,barcodeview 仍会通过继续从后台扫描来“困扰”您。你通常不想要的。即使您使用布尔标志来阻止扫描仪在焦点从扫描仪上移开后执行任何操作,它仍然会给您的处理器带来负担并减慢您的 UI,因为仍然有一个进程在后台不断解密高分辨率图像.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-08
        • 2016-04-10
        相关资源
        最近更新 更多