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

Android自定义ImageView:绘制圆形后填充底部30%并在顶部70%放置图片

实现自定义圆形ImageView:底部30%填充+顶部70%显示图片

核心思路

要实现需求,分三步处理:

  • 绘制圆形底部30%的填充区域
  • 裁剪画布,让ImageView的图片仅显示在圆形顶部70%的区域
  • 保留原有逻辑绘制圆形边框

完整实现代码

class CustomCircleImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ImageView(context, attrs, defStyleAttr) {

    private lateinit var radiusPaint: Paint
    private val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private lateinit var fillPath: Path
    private lateinit var clipPath: Path
    private var mWidth = 0
    private var mHeight = 0
    private var mRadius = 0f
    private var borderWidth = 4f // 可根据需求调整边框宽度
    private var classificationText: String = "" // 用于获取填充/边框颜色的分类文本

    init {
        initPaints()
    }

    private fun initPaints() {
        radiusPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mWidth = w
        mHeight = h
        // 计算圆形半径:减去边框宽度的一半,避免边框超出View范围
        mRadius = min(w, h) / 2f - borderWidth / 2f

        // 构建底部30%填充区域的路径:从完整圆形中减去顶部70%的矩形
        fillPath = Path().apply {
            addCircle(mWidth / 2f, mHeight / 2f, mRadius, Path.Direction.CW)
            // 顶部70%区域的矩形:从View顶部到圆形中心+0.4*半径的位置
            val topRect = RectF(0f, 0f, mWidth.toFloat(), mHeight / 2f + mRadius * 0.4f)
            op(topRect, Path.Op.DIFFERENCE)
        }

        // 构建图片裁剪路径:从完整圆形中减去底部30%的矩形
        clipPath = Path().apply {
            addCircle(mWidth / 2f, mHeight / 2f, mRadius, Path.Direction.CW)
            // 底部30%区域的矩形:从圆形中心+0.4*半径的位置到View底部
            val bottomRect = RectF(0f, mHeight / 2f + mRadius * 0.4f, mWidth.toFloat(), mHeight.toFloat())
            op(bottomRect, Path.Op.DIFFERENCE)
        }
    }

    override fun onDraw(canvas: Canvas?) {
        canvas ?: return

        // 1. 绘制底部30%填充区域
        fillPaint.color = getClassificationColor(classificationText)
        fillPaint.style = Paint.Style.FILL
        canvas.drawPath(fillPath, fillPaint)

        // 2. 裁剪画布,仅保留顶部70%圆形区域,绘制图片
        canvas.save()
        canvas.clipPath(clipPath)
        super.onDraw(canvas) // 调用ImageView原生绘制逻辑,图片会被限制在裁剪区域内
        canvas.restore()

        // 3. 绘制圆形边框(保留原有逻辑)
        radiusPaint.color = getClassificationColor(classificationText)
        radiusPaint.style = Paint.Style.STROKE
        radiusPaint.strokeWidth = borderWidth
        canvas.drawCircle(mWidth / 2f, mHeight / 2f, mRadius, radiusPaint)
    }

    // 替换为你实际的颜色获取逻辑
    private fun getClassificationColor(text: String): Int {
        return Color.RED
    }
}

关键细节说明

  1. 路径计算逻辑:

    • 圆形垂直范围为centerY - mRadius到centerY + mRadius,总高度2*mRadius
    • 底部30%区域高度为0.6*mRadius,因此该区域顶部Y坐标为centerY + 0.4*mRadius
    • 通过Path.Op.DIFFERENCE运算,从完整圆形中剔除不需要的区域,得到目标路径
  2. 画布裁剪:

    • 用canvas.save()和canvas.restore()维护画布状态,避免裁剪影响后续边框绘制
    • 裁剪后调用super.onDraw(canvas),ImageView的图片会自动适配裁剪区域,仅显示顶部70%的圆形部分
  3. 边框适配:

    • 计算mRadius时减去borderWidth/2,确保边框不会超出View可视范围,避免被截断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 00:40:41