安卓端如何实现Gpay QR Scanner同款扫描框边角样式?
安卓实现GPay同款二维码扫描框边角样式方案

方案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
相关产品推荐
相关产品推荐

