🫥

[Flutter]QRのバーコードスキャンをカスタマイズ!CustomQrBorderで背景透明化とボーダー表示を両立する方法

に公開

はじめに

FlutterでQRコードスキャナーを実装する際、デザインのカスタマイズで悩むことがありませんか?特に、背景を透明にしつつ、スキャンエリアのボーダーを美しく表示したい場合、標準的な方法では限界があります。

この記事では、qr_code_scannerパッケージの制約を克服し、カスタムボーダーを実装する方法を詳しく解説します。

問題点:標準的な実装の限界

通常、QRコードスキャナーでオーバーレイを透明にしようとすると、以下のような実装になります:

QrScannerOverlayShape(
  cutOutSize: 250,
  overlayColor: Colors.transparent,
),

しかし、この方法には大きな問題があります。overlayColor: Colors.transparentにしてしまうと、ボーダーまで消えてしまい、背景を透明にしつつボーダーを残すことができません。

これでは、ユーザーがスキャンエリアを認識しにくくなってしまいます。

解決策:CustomQrBorderの提案

そこで提案するのが、CustomQrBorderを使用したカスタム実装です。この方法を使うことで、背景を透明にしつつボーダーを残すことができます。

実装方法

実装の核心は、Stackで重ねて呼び出すことです:

return Stack(
  children: [
    QRView(
      key: qrKey,
      onQRViewCreated: _onQRViewCreated,
      overlay: QrScannerOverlayShape(
        cutOutSize: 250,
        overlayColor: Colors.transparent,
      ),
      onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
    ),
    Align(
      alignment: Alignment.center,
      child: CustomPaint(
        painter: CustomQrBorder(
          borderColor: AppColors.corporateColorLight,
          borderWidth: 10,
          borderRadius: 20,
          borderLength: 50,
          cutOutSize: 250,
        ),
        child: const SizedBox(),
      ),
    )
  ],
);

この実装により、QRViewの上にCustomPaintを重ねて、カスタムボーダーを描画しています。

CustomQrBorderの詳細解説

クラス構成

CustomQrBorderはCustomPainterを継承したクラスで、以下のパラメータを持ちます:

class CustomQrBorder extends CustomPainter {
  CustomQrBorder({
    this.borderColor = Colors.teal,      // ボーダーの色
    this.borderWidth = 4.0,              // ボーダーの太さ
    this.borderRadius = 8.0,             // 角の丸み
    this.borderLength = 30,              // L字の長さ
    this.cutOutSize = 250,               // スキャンエリアのサイズ
  });
}

パラメータの詳細

  • borderColor: ボーダーの色を指定。テーマカラーのAppColors.corporateColorLightを使用することで、アプリ全体のデザインとの一貫性を保てます
  • borderWidth: ボーダーの太さ。視認性を考慮して10pxに設定
  • borderRadius: 角の丸み。現代的なデザインに合わせて20pxに設定
  • borderLength: L字型ボーダーの長さ。50pxでバランスの良い表示
  • cutOutSize: スキャンエリアのサイズ。QRViewの設定と合わせる必要があります

描画ロジック

CustomQrBorderの描画処理は以下の手順で行われます:

1. ペイント設定

final borderPaint = Paint()
  ..color = borderColor
  ..style = PaintingStyle.stroke
  ..strokeWidth = borderWidth
  ..strokeCap = StrokeCap.round; // 角を丸くする

StrokeCap.roundにより、線の端を丸くして洗練された見た目にしています。

2. スキャンエリアの計算

final cutOutRect = Rect.fromCenter(
  center: Offset(size.width / 2, size.height / 2),
  width: cutOutSize,
  height: cutOutSize,
);

画面中央を基準に正方形のスキャンエリアを定義します。

3. 4つのL字型ボーダーの描画

各コーナーにL字型のボーダーを描画します:

左上のL字

final topLeftPath = Path()
  ..moveTo(cutOutRect.left, cutOutRect.top + borderLength)
  ..lineTo(cutOutRect.left, cutOutRect.top + borderRadius)
  ..arcToPoint(
    Offset(cutOutRect.left + borderRadius, cutOutRect.top),
    radius: Radius.circular(borderRadius),
  )
  ..lineTo(cutOutRect.left + borderLength, cutOutRect.top);

右上のL字

final topRightPath = Path()
  ..moveTo(cutOutRect.right - borderLength, cutOutRect.top)
  ..lineTo(cutOutRect.right - borderRadius, cutOutRect.top)
  ..arcToPoint(
    Offset(cutOutRect.right, cutOutRect.top + borderRadius),
    radius: Radius.circular(borderRadius),
  )
  ..lineTo(cutOutRect.right, cutOutRect.top + borderLength);

左下と右下のL字も同様に、clockwise: falseパラメータを使用して反時計回りのアーチを描画しています。

再描画の最適化


bool shouldRepaint(covariant CustomQrBorder oldDelegate) {
  return oldDelegate.borderColor != borderColor ||
      oldDelegate.borderWidth != borderWidth ||
      oldDelegate.borderRadius != borderRadius ||
      oldDelegate.borderLength != borderLength ||
      oldDelegate.cutOutSize != cutOutSize;
}

パラメータが変更された場合のみ再描画することで、パフォーマンスを最適化しています。

実装時のポイント

1. カラーの統一

borderColor: AppColors.corporateColorLight,

アプリのテーマカラーを使用することで、デザインの一貫性を保ちます。

2. サイズの同期

QRViewのcutOutSizeとCustomQrBorderのcutOutSizeを同じ値(250)に設定することが重要です。

3. Stackの順序

QRViewを先に配置し、その上にCustomPaintを重ねることで、カメラ映像の上にボーダーが描画されます。

実装のメリット

  1. デザインの自由度: 標準のQrScannerOverlayShapeでは不可能な、背景透明化とボーダー表示の両立
  2. カスタマイズ性: 色、太さ、角の丸み、サイズなど全てカスタマイズ可能
  3. パフォーマンス: CustomPainterによる効率的な描画
  4. テーマ対応: AppColorsを使用することで、ダークモード等のテーマ変更に対応

まとめ

CustomQrBorderを使用することで、QRコードスキャナーのデザインを大幅に改善できます。標準的な実装では実現できない、背景透明化とボーダー表示の両立が可能になり、ユーザーエクスペリエンスの向上につながります。

この実装パターンは、他のカスタムオーバーレイにも応用できるため、ぜひ参考にしてみてください。

Discussion