Jetpack Compose 是新 Android 應(yīng)用程序的首選 UI 框架。它的聲明式編程模型使編寫(xiě)漂亮的用戶界面變得輕而易舉。但是,如果您想重用依賴(lài)于傳統(tǒng)View系統(tǒng)的現(xiàn)有代碼怎么辦?多年來(lái),已經(jīng)開(kāi)發(fā)出無(wú)數(shù)精彩的定制組件。有一天可能會(huì)有它們的 Compose 版本。但是,無(wú)需等待。Jetpack Compose 包含功能強(qiáng)大但易于使用的互操作性 API。
在這篇簡(jiǎn)短的文章中,我將向您展示如何將 ZXing Android Embedded 集成到 Compose 應(yīng)用程序中。該示例應(yīng)用程序是我即將出版的《使用 Jetpack Compose 進(jìn)行 Android UI 開(kāi)發(fā)》一書(shū)的一部分。它將由 Packt 發(fā)布,預(yù)計(jì) 2022 年初可用。您可以在GitHub 上找到源代碼。
ZxingDemo使用基于 ZXing 解碼器的ZXing Android Embedded Barcode Scanner library for Android。它是根據(jù) Apache-2.0 許可條款發(fā)布的,并托管在GitHub 上。
ZximgDemo的目的是展示Views 在 Compose 應(yīng)用程序中的集成,而不是真正提供有用的應(yīng)用程序。它使用 ZXing Android Embedded 連續(xù)掃描 Barcodes 和 QR-Codes 并將結(jié)果打印在屏幕上。
要使用該庫(kù),只需將其作為實(shí)現(xiàn)依賴(lài)項(xiàng)添加到您的模塊級(jí)build.gradle文件中。
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
我們需要訪問(wèn)相機(jī),所以我們需要請(qǐng)求權(quán)限。這是這樣做的首選方法:
private lateinit var barcodeView: DecoratedBarcodeView
private val requestPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
barcodeView.resume()
}
}
override fun onResume() {
super.onResume()
requestPermission.launch(Manifest.permission.CAMERA)
}
override fun onPause() {
super.onPause()
barcodeView.pause()
}
ActivityResultContracts.RequestPermission替換圍繞覆蓋的過(guò)程onRequestPermissionsResult()。
barcodeView在 中初始化onCreate()。讓我們來(lái)看看。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val beepManager = BeepManager(this)
val root = layoutInflater.inflate(R.layout.layout, null)
barcodeView = root.findViewById(R.id.barcode_scanner)
val formats = listOf(BarcodeFormat.QR_CODE, BarcodeFormat.CODE_39)
barcodeView.barcodeView.decoderFactory = DefaultDecoderFactory(formats)
barcodeView.initializeFromIntent(intent)
val callback = object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) {
if (result.text == null || result.text == text.value) {
return
}
text.value = result.text
beepManager.playBeepSoundAndVibrate()
}
}
barcodeView.decodeContinuous(callback)
setContent {
val state = text.observeAsState()
state.value?.let {
ZxingDemo(root, it)
}
}
}
barcodeView引用組件樹(shù)中的一個(gè)子元素,我使用 膨脹layoutInflater.inflate()并分配給root. 布局(R.layout.layout代表layout.xml)非常簡(jiǎn)單:
<?xml version="1.0" encoding="utf-8"?>
<com.journeyapps.barcodescanner.DecoratedBarcodeView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true" />
因此,條形碼視圖DecoratedBarcodeView作為其子項(xiàng)之一提供。一旦我們獲得了對(duì)孩子的引用,我們就對(duì)其進(jìn)行配置。您可以在 ZXing Android Embedded 文檔中找到更多信息。
特定于 Compose 的部分發(fā)生在setContent {}.
- 我們使用創(chuàng)建狀態(tài)
observeAsState() - 我們調(diào)用一個(gè)可組合的命名
ZxingDemo()并傳遞狀態(tài)的值,并且root
text定義如下:
private val text = MutableLiveData("")
callback當(dāng)掃描儀引擎提供結(jié)果時(shí),它會(huì)在內(nèi)部更新。
在我們看之前ZxingDemo(),讓我們簡(jiǎn)要回顧一下:
-
root代表掃描儀 ui - 當(dāng)掃描儀有結(jié)果時(shí),它會(huì)更新
text(一個(gè)MutableLiveData實(shí)例 -
ZxingDemo()接收基于text掃描儀 ui 和根的狀態(tài)值
現(xiàn)在是時(shí)候看看如何實(shí)現(xiàn)集成了:
@Composable
fun ZxingDemo(root: View, value: String) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
AndroidView(modifier = Modifier.fillMaxSize(),
factory = {
root
})
if (value.isNotBlank()) {
Text(
modifier = Modifier.padding(16.dp),
text = value,
color = Color.White,
style = MaterialTheme.typography.h4
)
}
}
}
我們定義 aBox()有兩個(gè)孩子,AndroidView()并且Text()。AndroidView()接收一個(gè)工廠,它只是返回root(掃描儀 ui)。文檔說(shuō):
組成一個(gè)
View從factory. 該factory塊將只被調(diào)用一次以獲得View要組合的塊,并且它也保證在 UI 線程上被調(diào)用。因此,除了創(chuàng)建factory,該塊還可用于執(zhí)行一次性初始化和查看常量屬性的設(shè)置。
您可能想知道為什么我在 lambda 中onCreate()而不是在factorylambda 中膨脹對(duì)象樹(shù)。好吧,配置條形碼掃描儀不應(yīng)該在可組合中完成,因?yàn)樗赡苁枪逃械模?zhǔn)備相機(jī)和預(yù)覽,...)。此外,組件樹(shù)的某些部分是從外部訪問(wèn)的(在活動(dòng)級(jí)別上),因此無(wú)論如何我們都需要對(duì)子項(xiàng)的引用(barcodeView.
您還可以提供一個(gè)update塊,我的示例沒(méi)有。它在factory塊完成后立即運(yùn)行,并且由于重組可以運(yùn)行多次。您可以使用它來(lái)設(shè)置View屬性,具體取決于狀態(tài)。
我的應(yīng)用程序的 Compose 部分不會(huì)改變需要應(yīng)用于掃描儀組件樹(shù)的狀態(tài)。
結(jié)論
正如ZxingDemo所示,集成提供自定義組件的庫(kù)非常容易。您需要構(gòu)建代碼的結(jié)構(gòu)取決于庫(kù)的設(shè)置和配置方式。您是否打算使用 Jetpack Compose 互操作 API?請(qǐng)?jiān)谠u(píng)論中分享您的想法。
作者:Thomas Künneth
鏈接:https://dev.to/tkuenneth/integrating-zxing-android-embedded-in-a-compose-app-5ela