简体   繁体   English

Android:Canvas Arc,可以扫描渐变起始角度吗?

[英]Android: Canvas Arc, Can Sweep Gradient Start Angle Be Changed?

I am attempting to draw a arc that is filled by a gradient 我试图绘制一个由渐变填充的弧

The image below is what I want 下面的图像是我想要的

在此输入图像描述

The image below is what I have now 下图是我现在拥有的

在此输入图像描述

As you can see in the images, my gradient starts too earlier 正如您在图像中看到的那样,我的渐变开始得太早了

I know why this happening 我知道为什么会这样

If I complete the arc to form a circle I get this 如果我完成弧形成一个圆圈,我得到这个

在此输入图像描述

As we can see, the gradient starts from 90 degrees. 我们可以看到,渐变从90度开始。 But my arc is drawn from 135 degrees and sweeps to 270 但我的弧度是从135度绘制并扫到270

My question is how can get the gradient to start from 135 degrees and sweep to 270? 我的问题是如何让渐变从135度开始并扫到270? Is it possible 可能吗

This is my method so far of doing the sweep gradient 到目前为止,这是我执行扫描渐变的方法

  public void setProgressColourAsGradient(boolean invalidateNow) {
        SweepGradient sweepGradient = new SweepGradient(baseArcRect.centerX(), baseArcRect.centerY(),progressGradientColourStart,progressGradientColourEnd);
        //Make the gradient start from 90 degrees
        Matrix matrix = new Matrix();
        matrix.setRotate(90,baseArcRect.centerX(), baseArcRect.centerY());
        sweepGradient.setLocalMatrix(matrix);

        progressFillPaint.setShader(sweepGradient);
        if (invalidateNow) {
            invalidate();
        }
    }

I cannot find any API to tell SweepGradient where to actually start. 我找不到任何API来告诉SweepGradient实际启动的位置。

I have added all code to the appendix section 我已将所有代码添加到附录部分

Thanks for reading! 谢谢阅读!

Comment 1 评论1

I tried setting the rotation to happen at 135 degrees 我尝试将旋转设置为135度

在此输入图像描述

Appendix A ArcWithGradient View 附录A ArcWithGradient视图

public class ArcWithGradient extends View {

    private Paint progressFillPaint;
    private RectF baseArcRect;
    private int progressGradientColourStart;
    private int progressGradientColourEnd;
    /**
     * Thickness of the arc
     */
    private int thickness;

    public ArcWithGradient(Context context) {
        super(context);
        init();
    }

    public ArcWithGradient(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ArcWithGradient(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {

        progressGradientColourStart = ContextCompat.getColor(getContext(), R.color.pinnacle_gradient_start);
        progressGradientColourEnd = ContextCompat.getColor(getContext(), R.color.pinnacle_gradient_end);
        thickness = UiUtils.dpToPx(getContext(), 25);

        //We do not want a colour for this because we will set a gradient
        progressFillPaint = CanvasUtil.makeStrokePaint(UiUtils.dpToPx(getContext(), 25), -1);
        baseArcRect = new RectF(0, 0, 0, 0);
        setProgressColourAsGradient(false);
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
        super.onSizeChanged(width, height, oldw, oldh);
        //Ensures arc is within the rectangle
        float radius = Math.min(width, height) / 2;//

        //I do radius - thickness so that the arc is within the rectangle
        float baseArcLeft = ((width / 2) - (radius - thickness));
        float baseArcTop = ((height / 2) - (radius - thickness));
        float baseArcRight = ((width / 2) + (radius - thickness));
        float baseArcBottom = ((height / 2) + (radius - thickness));

        baseArcRect.set(baseArcLeft, baseArcTop, baseArcRight, baseArcBottom);
        //Recalculate the gradient
        setProgressColourAsGradient(false);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawArc(baseArcRect, 135, 270, false, progressFillPaint);
    }

    public void setProgressColourAsGradient(boolean invalidateNow) {
        SweepGradient sweepGradient = new SweepGradient(baseArcRect.centerX(), baseArcRect.centerY(),progressGradientColourStart,progressGradientColourEnd);
        //Make the gradient start from 90 degrees
        Matrix matrix = new Matrix();
        matrix.setRotate(90,baseArcRect.centerX(), baseArcRect.centerY());
        sweepGradient.setLocalMatrix(matrix);

        progressFillPaint.setShader(sweepGradient);
        if (invalidateNow) {
            invalidate();
        }
    }
}

Appendix B UiUtils 附录B UiUtils

public class UiUtils {

    public static int dpToPx(Context ctx, float dp) {
        return Math.round(dp * ctx.getResources().getDisplayMetrics().density);
    }
}

Appendix C CanvasUtil 附录C CanvasUtil

public class CanvasUtil {

    public static Paint makeStrokePaint(int width, int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.SQUARE);
        paint.setStrokeWidth(width);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(color);
        return paint;
    }

    public static Paint makeFillPaint(int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(color);
        return paint;
    }

} }

As mentioned in the comments by @pskink you need to use the SweepGradient constructor that takes a list of colors and a list of positions. 正如@pskink的评论中所提到的,你需要使用SweepGradient构造函数来获取颜色列表和位置列表。 The positions argument is an array of floats that indicate the percentage of 360 degrees where the color should begin. position参数是一个浮点数组,表示颜色应该开始的360度的百分比。

SweepGradient示例

In my example I'm rotating the canvas 115 degrees and then drawing a sweep angle of 310 degrees for my arch. 在我的例子中,我将画布旋转115度,然后为我的拱形绘制310度的扫掠角。 The first color begins at an angle of 0 (because the canvas has been rotated), and the gradient reaches the second color at an angle of 310 degrees so it matches the sweep angle of the arch. 第一种颜色从0开始(因为画布已经旋转),并且渐变以310度的角度到达第二种颜色,因此它与拱的扫掠角匹配。 The outer ring shows that the blue color continues all the way to 360 degrees, but the blue color begins at 310 degrees. 外圈显示蓝色一直延续到360度,但蓝色从310度开始。

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


    private val archPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeWidth = 32 * context.resources.displayMetrics.density
    }

    private val archBounds = RectF()
    private val archInset = 72 * context.resources.displayMetrics.density

    private val gradientColors = intArrayOf(Color.MAGENTA, Color.BLUE)
    private val gradientPositions = floatArrayOf(0/360f, 310/360f)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        val size = Math.min(width, height)
        setMeasuredDimension(size, size)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        archPaint.shader = SweepGradient(width / 2f, height / 2f, gradientColors, gradientPositions)
        archBounds.set(archInset, archInset, width.toFloat() - archInset, height.toFloat() - archInset)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val cx = width / 2f
        val cy = height / 2f

        canvas.save()
        canvas.rotate(115f, cx, cy)
        canvas.drawArc(archBounds, 0f, 310f, false, archPaint)
        canvas.drawCircle(cx, cy, width / 2.2f, archPaint)
        canvas.restore()
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM