精品一区二区三区在线成人,欧美精产国品一二三区,Ji大巴进入女人66h,亚洲春色在线视频

炫酷!讓Android同時(shí)掃多個(gè)二維碼的魔法揭秘

移動(dòng)開(kāi)發(fā) Android
超市里別人還在一個(gè)一個(gè)掃商品二維碼,你的APP卻能"唰"一下瞬間識(shí)別整排商品!今天教大家用Google的黑科技MLKit+CameraX,輕松實(shí)現(xiàn)這個(gè)超酷功能。別擔(dān)心,跟著做絕對(duì)能搞定!

想象一下:超市里別人還在一個(gè)一個(gè)掃商品二維碼,你的APP卻能"唰"一下瞬間識(shí)別整排商品!今天教大家用Google的黑科技MLKit+CameraX,輕松實(shí)現(xiàn)這個(gè)超酷功能。別擔(dān)心,跟著做絕對(duì)能搞定~

準(zhǔn)備工作:裝備你的"魔法棒"

// build.gradle 添加這些"魔法材料"
dependencies {
    implementation 'androidx.camera:camera-camera2:1.3.1'       // 相機(jī)核心
    implementation 'androidx.camera:camera-lifecycle:1.3.1'      // 生命周期管家
    implementation 'androidx.camera:camera-view:1.3.1'  // 取景器
    implementation 'com.google.mlkit:barcode-scanning:17.1.0'   // 二維碼識(shí)別引擎
}
<!-- AndroidManifest.xml 申請(qǐng)相機(jī)權(quán)限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />

?? 就像哈利波特需要魔杖,這些就是我們的"魔法裝備"!記得先在手機(jī)設(shè)置里開(kāi)啟相機(jī)權(quán)限哦~

搭建舞臺(tái):創(chuàng)建掃描界面

<!-- activity_main.xml 布置舞臺(tái) -->
<androidx.camera.view.PreviewView
    android:id="@+id/viewFinder"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

?? 這個(gè)全屏"魔法鏡"就是我們的掃描窗口,用戶看到的實(shí)時(shí)畫面都在這里顯示

核心魔法:二維碼識(shí)別器

class QRCodeAnalyzer(privateval onDetect: (List<Barcode>) -> Unit) : ImageAnalysis.Analyzer {

    // 設(shè)置只識(shí)別二維碼(避免誤認(rèn)條形碼)
    privateval options = BarcodeScannerOptions.Builder()
        .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
        .build()

    privateval scanner = BarcodeScanning.getClient(options)  // 創(chuàng)建識(shí)別器實(shí)例

    @SuppressLint("UnsafeExperimentalUsageError")
    overridefun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        mediaImage?.let { 
            // 將相機(jī)畫面轉(zhuǎn)為可識(shí)別格式
            val image = InputImage.fromMediaImage(it, imageProxy.imageInfo.rotationDegrees)
            scanImage(image, imageProxy)  // 開(kāi)始掃描!
        }
    }

    privatefun scanImage(image: InputImage, imageProxy: ImageProxy) {
        scanner.process(image)
            .addOnSuccessListener { codes -> 
                onDetect(codes)  // 成功抓到所有二維碼!
            }
            .addOnCompleteListener { 
                imageProxy.close()  // 關(guān)閉當(dāng)前幀,準(zhǔn)備下一幀
            }
    }
}

?? 這段代碼就像訓(xùn)練了一只"二維碼獵犬":

analyze()負(fù)責(zé)轉(zhuǎn)換相機(jī)畫面格式

scanImage()釋放獵犬識(shí)別二維碼

? 識(shí)別完成后自動(dòng)重置準(zhǔn)備下次狩獵

啟動(dòng)魔法:把一切組裝起來(lái)

class MainActivity : AppCompatActivity() {
    private val cameraExecutor = Executors.newSingleThreadExecutor()  // 專用工作線程
    private val viewFinder by lazy { findViewById<PreviewView>(R.id.viewFinder) }

    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener({
            val cameraProvider = cameraProviderFuture.get()
            
            // 創(chuàng)建預(yù)覽畫面
            val preview = Preview.Builder().build().apply {
                setSurfaceProvider(viewFinder.surfaceProvider)
            }

            // 創(chuàng)建二維碼識(shí)別管道
            val qrAnalyzer = ImageAnalysis.Builder().build().apply {
                setAnalyzer(cameraExecutor, QRCodeAnalyzer { codes ->
                    // 識(shí)別結(jié)果回調(diào)區(qū) ▼
                    codes.forEachIndexed { index, code ->
                        Log.d("QR_DEBUG", "抓到二維碼 ${index + 1}: ${code.rawValue}")
                    }
                })
            }

            try {
                // 組裝所有部件!啟動(dòng)!
                cameraProvider.unbindAll()
                cameraProvider.bindToLifecycle(
                    this, 
                    CameraSelector.DEFAULT_BACK_CAMERA,  // 使用后置攝像頭
                    preview,
                    qrAnalyzer
                )
            } catch (e: Exception) {
                Log.e("CAMERA", "啟動(dòng)失敗", e)
            }
        }, ContextCompat.getMainExecutor(this))
    }
}

啟動(dòng)流程四步走:

? 獲取相機(jī)控制權(quán)

? 設(shè)置預(yù)覽窗口

? 連接二維碼識(shí)別器

? 啟動(dòng)整個(gè)系統(tǒng)!

圖片圖片

圖片圖片


讓掃描結(jié)果躍然屏上

想要把掃描到的二維碼信息實(shí)時(shí)展示出來(lái)?小菜一碟!

<!-- 結(jié)果展示層 -->
<LinearLayout
    android:id="@+id/resultsContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:orientation="vertical"
    android:background="#80000000"
    android:padding="16dp">
        
    <TextView
        android:id="@+id/tvHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="掃描結(jié)果"
        android:textColor="#4CAF50"
        android:textSize="18sp"
        android:textStyle="bold"/>
        
    <LinearLayout
        android:id="@+id/resultsLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginTop="8dp"/>
</LinearLayout>

設(shè)計(jì)思路:動(dòng)態(tài)添加識(shí)別到的每個(gè)二維碼信息

在MainActivity中添加處理邏輯:

// 獲取布局元素引用
private val resultsLayout by lazy { findViewById<LinearLayout>(R.id.resultsLayout) }
private val resultsContainer by lazy { findViewById<LinearLayout>(R.id.resultsContainer) }
    
// 顯示掃描結(jié)果的核心方法
private fun showScanResults(codes: List<Barcode>) {
    // 清空之前的結(jié)果
    resultsLayout.removeAllViews()
        
    if (codes.isEmpty()) {
        // 沒(méi)有掃描到結(jié)果時(shí)顯示提示
        val emptyView = TextView(this).apply {
            text = "???♀? 正在尋找二維碼..."
            setTextColor(Color.WHITE)
        }
        resultsLayout.addView(emptyView)
        return
    }

    // 動(dòng)態(tài)添加每個(gè)二維碼結(jié)果
    codes.forEachIndexed { index, barcode ->
        val resultView = createResultView(barcode, index)
        resultsLayout.addView(resultView)
    }
}

// 創(chuàng)建單個(gè)結(jié)果視圖
private fun createResultView(barcode: Barcode, index: Int): TextView {
    return TextView(this).apply {
        // 解析二維碼內(nèi)容
        val content = barcode.rawValue ?: "未知內(nèi)容"
            
        // 格式化顯示文本
        text = "? 二維碼 ${index + 1}:\n${content.take(50)}${if (content.length > 50) "..." else ""}"
        setTextColor(Color.WHITE)
        setTypeface(null, Typeface.BOLD)
        textSize = 14f
            
        // 添加點(diǎn)擊事件查看完整內(nèi)容
        setOnClickListener {
            AlertDialog.Builder(this@MainActivity)
                .setTitle("二維碼詳情")
                .setMessage(content)
                .setPositiveButton("復(fù)制") { _, _ ->
                    copyToClipboard(content)
                    Toast.makeText(this@MainActivity, "已復(fù)制到剪貼板", Toast.LENGTH_SHORT).show()
                }
                .setNegativeButton("關(guān)閉", null)
                .show()
        }
    }
}
    
// 復(fù)制到剪貼板工具方法
private fun copyToClipboard(text: String) {
    val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    val clip = ClipData.newPlainText("二維碼內(nèi)容", text)
    clipboard.setPrimaryClip(clip)
}

圖片圖片

超實(shí)用小技巧

性能優(yōu)化:在ImageAnalysis.Builder()后加上.setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)避免卡頓

多類型支持:修改.setBarcodeFormats()可同時(shí)識(shí)別條形碼/二維碼

聚焦區(qū)域:添加viewFinder.setOnTouchListener實(shí)現(xiàn)點(diǎn)擊聚焦

// 添加點(diǎn)擊聚焦功能
viewFinder.setOnTouchListener { _, event ->
    if (event.action == MotionEvent.ACTION_DOWN) {
        val factory = viewFinder.meteringPointFactory
        val point = factory.createPoint(event.x, event.y)
        CameraControl?.startFocusAndMetering(FocusMeteringAction.Builder(point).build())
    }
    true
}

CameraX搭舞臺(tái),ML Kit來(lái)識(shí)別,異步處理不卡頓,多碼掃描So Easy!

現(xiàn)在你的APP已經(jīng)擁有"火眼金睛"啦!快去試試同時(shí)掃描一排二維碼的爽快感吧~

源碼https://github.com/Reathin/Sample-Android/tree/master/module_mlkit_barcode_scanning

責(zé)任編輯:武曉燕 來(lái)源: 沐雨花飛碟
相關(guān)推薦

2023-12-25 14:53:36

2022-03-24 09:43:29

二維碼二維碼修改器github

2023-08-08 14:16:07

二維碼開(kāi)發(fā)鴻蒙

2024-06-26 08:46:45

2013-12-03 10:32:52

2013-01-30 12:16:49

二維碼NFC近場(chǎng)通訊

2013-11-26 09:54:02

2024-03-07 07:59:37

2013-03-27 16:13:17

Android開(kāi)發(fā)Android二維碼生QR生成

2023-11-17 15:44:06

C++庫(kù)生成二維碼

2018-03-05 18:39:25

2021-09-08 10:02:56

面試二維碼前端

2023-05-09 20:41:00

網(wǎng)絡(luò)詐騙網(wǎng)絡(luò)安全

2023-11-17 09:07:51

.NET生成二維碼識(shí)別二維碼

2012-04-01 09:53:13

二維碼

2017-02-21 09:17:46

二維碼漏洞

2011-12-06 16:40:45

二維碼快拍二維碼靈動(dòng)快拍

2013-11-19 16:06:39

2011-11-24 16:00:23

信息圖QR碼二維碼

2013-01-30 12:12:20

微信二維碼智能手機(jī)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 龙岩市| 和林格尔县| 庄河市| 万盛区| 油尖旺区| 肥西县| 黔西县| 邳州市| 淅川县| 葫芦岛市| 璧山县| 眉山市| 乌什县| 临泽县| 甘孜| 富宁县| 许昌市| 乌拉特后旗| 凌海市| 屏东市| 永兴县| 青冈县| 宾川县| 辽源市| 府谷县| 栾川县| 正宁县| 乡城县| 甘南县| 乳山市| 楚雄市| 唐山市| 临沂市| 咸宁市| 盐源县| 高台县| 疏附县| 靖州| 镇安县| 冕宁县| 丰都县|