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

Android Canvas绘制带渐变填充的曲线图形技术求助

嘿,我来帮你搞定这些Canvas绘图的问题!咱们一步步拆解你的需求,逐个解决:

1. 修正后的曲线绘制示例代码及参数解析

先看你原来的代码里,第二个圆弧的RectF超出了Canvas范围(Canvas高度只有300,你设的top是300,直接跑到画布外面去了),所以看不到。我给你调整了位置,还加了贝塞尔曲线的示例,方便你理解不同曲线的绘制方式:

public class DrawingActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawing);
        ImageView img = findViewById(R.id.img);

        // 创建画布,宽1000,高300
        Bitmap bitmap = Bitmap.createBitmap(1000, 300, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.LTGRAY);

        // 初始化描边画笔
        Paint strokePaint = new Paint();
        strokePaint.setColor(Color.RED);
        strokePaint.setStyle(Paint.Style.STROKE);
        strokePaint.setStrokeWidth(8);
        strokePaint.setAntiAlias(true);

        // 绘制第一条直线
        int centerY = canvas.getHeight() / 2;
        canvas.drawLine(0, centerY, 300, centerY, strokePaint);

        // 绘制第一个圆弧(左上)
        RectF oval1 = new RectF(250, 100, 300, 200);
        // 参数:椭圆边界RectF,起始角度,扫过角度,是否连接圆心,画笔
        canvas.drawArc(oval1, 90, -90, false, strokePaint);

        // 绘制第二个圆弧(中间,调整到画布可见范围内)
        RectF oval2 = new RectF(450, 150, 500, 250);
        canvas.drawArc(oval2, 90, -90, false, strokePaint);

        // 绘制二阶贝塞尔曲线(示例复杂曲线)
        Path bezierPath = new Path();
        bezierPath.moveTo(300, centerY); // 曲线起点
        bezierPath.quadTo(400, 50, 500, centerY); // 控制点(400,50),终点(500,centerY)
        strokePaint.setColor(Color.BLUE);
        canvas.drawPath(bezierPath, strokePaint);

        // 绘制第二条直线
        canvas.drawLine(500, canvas.getHeight() - 50, 1000, canvas.getHeight() - 50, strokePaint);

        img.setImageBitmap(bitmap);
    }
}

参数解释:

  • drawLine(startX, startY, stopX, stopY, paint):直接画直线,四个坐标分别是起点和终点的x/y值。
  • drawArc(oval, startAngle, sweepAngle, useCenter, paint):
    • oval:圆弧所在椭圆的边界矩形(后面详细讲)
    • startAngle:起始角度(0°对应3点钟方向,顺时针为正方向)
    • sweepAngle:圆弧扫过的角度(负数表示逆时针方向)
    • useCenter:如果为true,会把圆弧两端和椭圆中心连接,形成扇形;false只画弧本身。
  • drawPath(path, paint):通过Path对象绘制任意复杂曲线,示例里的quadTo是二阶贝塞尔曲线,需要一个控制点和终点。

2. 彻底搞懂drawArc的left/top/right/bottom参数

你提到的这四个参数是用来定义圆弧所在椭圆的外切矩形的:

  • left:矩形左侧边缘的x坐标
  • top:矩形顶部边缘的y坐标
  • right:矩形右侧边缘的x坐标
  • bottom:矩形底部边缘的y坐标

举个例子,你原来的oval.set(250, 100, 300,200):

  • 矩形的宽度是 300-250=50,高度是 200-100=100
  • 椭圆会刚好内切于这个矩形,所以是一个“竖长”的椭圆
  • 然后drawArc就是在这个椭圆上截取一段弧,角度参数决定了弧的位置和长度

简单说:这四个参数框出了椭圆的范围,椭圆的中心就是(left+right)/2, (top+bottom)/2,椭圆的长轴短轴由矩形的宽高决定。

3. 实现目标图形的渐变填充(仅填充指定图形)

要实现只给单个图形填渐变,核心是给Paint设置Shader,并且让Shader的范围和目标图形匹配。这里以第一个圆弧的渐变填充为例:

// 给第一个圆弧创建渐变填充画笔
Paint fillPaint = new Paint();
fillPaint.setAntiAlias(true);
// 创建线性渐变:从矩形左上角到右下角,颜色从红到黄
LinearGradient arcGradient = new LinearGradient(
        250, 100, // 渐变起始点x/y(对应oval1的left/top)
        300, 200, // 渐变结束点x/y(对应oval1的right/bottom)
        Color.RED, Color.YELLOW, // 起始和结束颜色
        Shader.TileMode.CLAMP // 超出渐变范围时的颜色填充模式
);
fillPaint.setShader(arcGradient);
// 绘制带渐变填充的扇形(useCenter设为true)
canvas.drawArc(oval1, 90, -90, true, fillPaint);

关键点:

  • 渐变的起始/结束坐标要和目标图形的RectF对应,这样渐变才会刚好覆盖图形
  • 如果是径向渐变,可以用RadialGradient,参数是圆心、半径、颜色组
  • 一定要把Paint的Style设为FILL(默认就是FILL,所以不用额外设置,除非之前设过STROKE)
  • Shader是绑定在Paint上的,所以不同图形需要不同的Paint(或者每次绘制前重新设置Shader)

这样就能实现只给目标图形填充渐变,而不会影响整个Canvas的背景啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:41:55