package com.sw.dualscreen.view import androidx.core.graphics.toColorInt import android.content.Context import android.graphics.* import android.util.AttributeSet import android.view.View /** * 带镂空椭圆的矩形自定义View * 矩形尺寸:400dp × 510dp,背景色 #FFF4FAFF * 镂空椭圆尺寸:400dp × 436dp,居中显示 */ class HollowOvalInRectView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { // 基础尺寸配置(dp) private val rectWidthDp = 400f // 矩形宽度 private val rectHeightDp = 510f // 矩形高度 private val ovalWidthDp = 400f // 椭圆宽度 private val ovalHeightDp = 436f // 椭圆高度 // 转换后的像素尺寸 private val rectWidth: Float private val rectHeight: Float private var ovalWidth: Float private var ovalHeight: Float // 矩形背景画笔(颜色 #FFF4FAFF) private val rectPaint = Paint().apply { isAntiAlias = true color = "#FFF4FAFF".toColorInt() // 矩形背景色 // color = "#FFFFFF".toColorInt() // 矩形背景色 style = Paint.Style.FILL } // 镂空椭圆画笔(核心:DST_OUT模式实现镂空) private val hollowOvalPaint = Paint().apply { isAntiAlias = true color = Color.BLACK // 颜色不影响镂空效果,仅需非透明即可 style = Paint.Style.FILL xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) } // 椭圆路径(复用避免重复创建) private val ovalPath = Path() init { // dp转px,保证多设备尺寸一致 val density = resources.displayMetrics.density rectWidth = rectWidthDp * density rectHeight = rectHeightDp * density ovalWidth = ovalWidthDp * density ovalHeight = ovalHeightDp * density // 关键配置:关闭硬件加速保证Xfermode生效 setLayerType(LAYER_TYPE_HARDWARE, null) // 视图背景透明,避免干扰 setBackgroundColor(Color.TRANSPARENT) } /** * 强制设置View尺寸为指定的矩形尺寸 */ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val targetWidth = MeasureSpec.makeMeasureSpec(rectWidth.toInt(), MeasureSpec.EXACTLY) val targetHeight = MeasureSpec.makeMeasureSpec(rectHeight.toInt(), MeasureSpec.EXACTLY) super.onMeasure(targetWidth, targetHeight) } /** * 核心绘制逻辑:先画矩形,再画镂空椭圆 */ override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 保存画布图层,确保Xfermode生效 val layerId = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null) // 1. 绘制底层矩形(背景色 #FFF4FAFF) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), rectPaint) // 2. 计算椭圆居中坐标(椭圆宽度和矩形宽度一致,仅垂直居中) val ovalTop = (rectHeight - ovalHeight) / 2 // 椭圆顶部偏移 val ovalBottom = ovalTop + ovalHeight // 椭圆底部坐标 // 3. 绘制镂空椭圆(居中) ovalPath.reset() ovalPath.addOval( 0f, // 左:和矩形左对齐(宽度一致) ovalTop, // 上:垂直居中 rectWidth, // 右:和矩形右对齐 ovalBottom, // 下 Path.Direction.CW ) canvas.drawPath(ovalPath, hollowOvalPaint) // 恢复画布状态 canvas.restoreToCount(layerId) } // 扩展方法:支持动态修改矩形背景色 fun updateRectBackgroundColor(colorHex: String) { try { rectPaint.color = Color.parseColor(colorHex) invalidate() // 重绘视图 } catch (e: IllegalArgumentException) { e.printStackTrace() } } // 扩展方法:支持动态修改椭圆尺寸(可选) fun updateOvalSize(widthDp: Float, heightDp: Float) { val density = resources.displayMetrics.density ovalWidth = widthDp * density ovalHeight = heightDp * density invalidate() } }