You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

安卓端如何实现Gpay QR Scanner同款扫描框边角样式?

安卓实现GPay同款二维码扫描框边角样式方案

GPay QR扫描框效果参考

方案1:通过Drawable+布局快速实现(无需自定义View)

  • 第一步:创建边角样式Drawable gpay_scan_corner.xml 存放到res/drawable目录
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 左上角横向边 -->
    <item android:gravity="top|left">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:topLeftRadius="2dp" />
            <size android:width="24dp" android:height="4dp" />
        </shape>
    </item>
    <!-- 左上角纵向边 -->
    <item android:gravity="top|left">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:topLeftRadius="2dp" />
            <size android:width="4dp" android:height="24dp" />
        </shape>
    </item>

    <!-- 右上角横向边 -->
    <item android:gravity="top|right">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:topRightRadius="2dp" />
            <size android:width="24dp" android:height="4dp" />
        </shape>
    </item>
    <!-- 右上角纵向边 -->
    <item android:gravity="top|right">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:topRightRadius="2dp" />
            <size android:width="4dp" android:height="24dp" />
        </shape>
    </item>

    <!-- 左下角横向边 -->
    <item android:gravity="bottom|left">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:bottomLeftRadius="2dp" />
            <size android:width="24dp" android:height="4dp" />
        </shape>
    </item>
    <!-- 左下角纵向边 -->
    <item android:gravity="bottom|left">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:bottomLeftRadius="2dp" />
            <size android:width="4dp" android:height="24dp" />
        </shape>
    </item>

    <!-- 右下角横向边 -->
    <item android:gravity="bottom|right">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:bottomRightRadius="2dp" />
            <size android:width="24dp" android:height="4dp" />
        </shape>
    </item>
    <!-- 右下角纵向边 -->
    <item android:gravity="bottom|right">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:bottomRightRadius="2dp" />
            <size android:width="4dp" android:height="24dp" />
        </shape>
    </item>
</layer-list>
  • 第二步:布局中嵌套扫描区域结构
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- 相机预览View -->
    <TextureView
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- 半透明遮罩+扫描框角 -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#99000000">
        <!-- 中间扫描区域 -->
        <FrameLayout
            android:id="@+id/scan_area"
            android:layout_width="250dp"
            android:layout_height="250dp"
            android:layout_gravity="center"
            android:background="@drawable/gpay_scan_corner" />
    </FrameLayout>
</FrameLayout>

该方案已经可以还原90%以上的GPay扫描框效果,尺寸、颜色参数可自行调整匹配设计要求。

方案2:自定义View实现(支持动画、更灵活)

如果需要添加扫描线动画、边角呼吸效果等交互,可以通过自定义View直接绘制:

class GPayScanView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    // 遮罩颜色
    private val maskColor = 0x99000000.toInt()
    // 边角颜色
    private val cornerColor = Color.WHITE
    // 边角厚度
    private val cornerThickness = 4.dpToPx()
    // 边角长度
    private val cornerLength = 24.dpToPx()
    // 边角圆角
    private val cornerRadius = 2.dpToPx()
    // 扫描区域大小
    private val scanAreaSize = 250.dpToPx()

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val cornerRect = RectF()

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val scanLeft = (width - scanAreaSize) / 2f
        val scanTop = (height - scanAreaSize) / 2f
        val scanRight = scanLeft + scanAreaSize
        val scanBottom = scanTop + scanAreaSize

        // 绘制半透明遮罩
        paint.color = maskColor
        canvas.drawRect(0f, 0f, width.toFloat(), scanTop, paint)
        canvas.drawRect(0f, scanBottom, width.toFloat(), height.toFloat(), paint)
        canvas.drawRect(0f, scanTop, scanLeft, scanBottom, paint)
        canvas.drawRect(scanRight, scanTop, width.toFloat(), scanBottom, paint)

        // 绘制四个边角
        paint.color = cornerColor
        paint.style = Paint.Style.FILL
        // 左上角
        cornerRect.set(scanLeft, scanTop, scanLeft + cornerLength, scanTop + cornerThickness)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)
        cornerRect.set(scanLeft, scanTop, scanLeft + cornerThickness, scanTop + cornerLength)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)

        // 右上角
        cornerRect.set(scanRight - cornerLength, scanTop, scanRight, scanTop + cornerThickness)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)
        cornerRect.set(scanRight - cornerThickness, scanTop, scanRight, scanTop + cornerLength)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)

        // 左下角
        cornerRect.set(scanLeft, scanBottom - cornerThickness, scanLeft + cornerLength, scanBottom)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)
        cornerRect.set(scanLeft, scanBottom - cornerLength, scanLeft + cornerThickness, scanBottom)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)

        // 右下角
        cornerRect.set(scanRight - cornerLength, scanBottom - cornerThickness, scanRight, scanBottom)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)
        cornerRect.set(scanRight - cornerThickness, scanBottom - cornerLength, scanRight, scanBottom)
        canvas.drawRoundRect(cornerRect, cornerRadius, cornerRadius, paint)
    }

    private fun Int.dpToPx(): Float {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), resources.displayMetrics)
    }
}

直接在布局中引入该自定义View即可使用。

内容的提问来源于stack exchange,提问作者Mohit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 02:18:05