はじめに
今回はzxing-android-embedded
を使ってQRコードの読み取り機能を実装します。
読み取り画面のレイアウトは、デフォルトのものを使うこともできますが、今回は色々とカスタマイズできるよう自作のレイアウトを適用するように実装します。以下は完成画面です。
実装
ライブラリの導入
build.gradle
のdependenciesに以下のように記述します。
dependencies {
implementation 'com.journeyapps:zxing-android-embedded:4.1.0'
//省略
}
AndroidManifest.xml
には以下を追加します。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<application
android:hardwareAccelerated="true" //ハードウェアアクセラレーションを有効にする
//省略
<activity
android:name=".QRCodeCaptureActivity"
android:exported="false" />
これで準備完了です。
TOP画面
次にアプリを起動した際に初期表示されるトップ画面を作成します。ボタンを押すと、QR読み取り画面が開きます。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/qr_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QRカメラ起動"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
次にボタンを押した際にQRカメラを起動するよう、clickListenerと読み取った結果をトーストで表示する実処理を書いていきます。
今回は自作のレイアウトを使用するため、QRCodeCaptureActivity
を起動するようにします。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var qrButton = findViewById<Button>(R.id.qr_button)
//ボタンを押した際QR読み取り画面に遷移する
qrButton.setOnClickListener{
IntentIntegrator(this).apply{
captureActivity=QRCodeCaptureActivity::class.java
}.initiateScan()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//読み取った結果の受け取り
val result = IntentIntegrator.parseActivityResult(resultCode,data)
if(result.contents != null){
//読み取った結果をトーストで表示する
Toast.makeText(this, result.contents, Toast.LENGTH_LONG).show()
}
}
}
QR読み取り画面
読み取り画面のレイアウトを作成します。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:zxing_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.journeyapps.barcodescanner.CompoundBarcodeView
android:id="@+id/qrcode_reader"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
zxing_view:zxing_scanner_layout="@layout/qr_code_reader"></com.journeyapps.barcodescanner.CompoundBarcodeView>
<TextView
android:id="@+id/qrTextView"
//省略
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zxing_barcode_view="http://schemas.android.com/apk/res-auto"
xmlns:zxing_finder="http://schemas.android.com/apk/res-auto"
>
<com.journeyapps.barcodescanner.BarcodeView
android:id="@+id/zxing_barcode_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
zxing_barcode_view:zxing_framing_rect_height="300dp"
zxing_barcode_view:zxing_framing_rect_width="300dp" />
<View
android:layout_width="305dp"
android:layout_height="305dp"
android:background="@drawable/qr_code_frame"
android:layout_gravity="center"></View>
<com.journeyapps.barcodescanner.ViewfinderView
android:id="@+id/zxing_viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
zxing_finder:zxing_possible_result_points="@color/zxing_transparent"
zxing_finder:zxing_result_view="@color/zxing_result_view"
zxing_finder:zxing_viewfinder_laser="@color/zxing_transparent"
zxing_finder:zxing_viewfinder_mask="@color/zxing_viewfinder_mask" />
</merge>
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="220dp"
android:height="220dp"
android:viewportHeight="230.0"
android:viewportWidth="230.0">
<path
android:pathData="M 0 0 H 230 V 230 H 0 Z"
android:fillType="evenOdd"
android:fillColor="#00000000"
android:strokeWidth="10"
android:strokeColor="@android:color/white" />
</vector>
最後に、QRCodeCaptureActivityを処理を書いていきます。
class QRCodeCaptureActivity : CaptureActivity() {
private lateinit var capture: CaptureManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_qrcode )
var barcodeScannerView = findViewById<com.journeyapps.barcodescanner.CompoundBarcodeView>(R.id.qrcode_reader)
// デフォルトで表示される赤い線を消す
disableLaser(barcodeScannerView!!)
var capture = CaptureManager(this, barcodeScannerView!!)
capture!!.initializeFromIntent(intent, savedInstanceState)
capture!!.decode()
}
override fun onResume() {
super.onResume()
var barcodeView = findViewById<com.journeyapps.barcodescanner.CompoundBarcodeView>(R.id.qrcode_reader)
barcodeView.resume()
}
override fun onPause() {
super.onPause()
var barcodeView = findViewById<com.journeyapps.barcodescanner.CompoundBarcodeView>(R.id.qrcode_reader)
barcodeView.pause()
}
override fun onDestroy() {
super.onDestroy()
var barcodeView = findViewById<com.journeyapps.barcodescanner.CompoundBarcodeView>(R.id.qrcode_reader)
barcodeView.pause()
}
// 赤い線を消す処理
private fun disableLaser(decoratedBarcodeView: DecoratedBarcodeView) {
val scannerAlphaField = ViewfinderView::class.java.getDeclaredField("SCANNER_ALPHA")
scannerAlphaField.isAccessible = true
scannerAlphaField.set(decoratedBarcodeView.viewFinder, intArrayOf(0))
}
}
これで実装完了です。実際にサンプルのQRコードを読み取ってみます。
※つまづいた点
ActivityのonResume()/onPause()でCompoundBarcodeViewのresume()/pause()を呼ぶことを忘れないよう注意してください。これをしないと画面を開いても真っ黒な画面にしかなりません。
最後に
以上になります。
デフォルトで用意されているレイアウトを使用すれば、もっと簡単に実装できますが、いかんせんできることに限りがあります。
かゆいところに手が届かないといった状況に陥らないためにも、最初から自作のレイアウトを適用しておくと、柔軟な開発ができるかと思います。
是非こちら参考にしていただけますと幸いです。