关于bezier:在android中绘制自定义视图

draw custom views in android

我想在 android 中绘制类似的东西,将其用作按钮。怎么做?任何链接或建议?是贝塞尔曲线吗?


如评论中所述,您可以创建一个 PNG 并直接使用它。如果您希望侧面独立于曲线缩放,您可以对图像进行 9-patch。

根据这篇文章,您现在可以选择在 xml 中定义可绘制的路径。但仅适用于 Lollipop 及以上。

最后,您可以创建一个基本按钮并使用 Path 对象来绘制二次曲线。例子。我自己没试过,但是你应该可以把浴缸下面的区域填满例子1,例子2。

编辑:

我有一点时间来创建一个 Path 实现的示例。为了填充路径下方的部分,需要使用剪辑。这对您来说不是一个精确的解决方案,但您应该能够通过调整一些变量(x1y1x2y2x3y3).

在我的实现中,我使用了渐变而不是纯色,因为它不会对实现产生影响,而且它是一个更通用的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
public class PathView extends View
{
    private Paint paintFill;
    private Paint paintLine;
    private Paint paintClear;
    private Path  path;
    private int   colour;

    private float x0;
    private float y0;
    private float x1;
    private float y1;
    private float x2;
    private float y2;
    private float x3;
    private float y3;

    public PathView(Context context)
    {
        super(context);
    }

    public PathView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public PathView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    public PathView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);

        initialize();
    }

    private void initialize()
    {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        {
            // Path clipping uses hardware acceleration which is unavailable from 11 to 18
            // https://stackoverflow.com/questions/8895677/work-around-canvas-clippath-that-is-not-supported-in-android-any-more
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }

        paintFill = new Paint();
        paintFill.setAntiAlias(true);
        LinearGradient gradient = new LinearGradient(0, getHeight(), 0, 0, Color.WHITE, colour, Shader.TileMode.CLAMP); // Vertical gradient
        paintFill.setShader(gradient);

        paintLine = new Paint();
        paintLine.setColor(colour);
        paintLine.setStrokeWidth(1.5f);
        paintLine.setStrokeCap(Paint.Cap.ROUND);
        paintLine.setStyle(Paint.Style.STROKE);
        paintLine.setAntiAlias(true);

        paintClear = new Paint();
        paintClear.setColor(Color.WHITE);
        paintClear.setAntiAlias(true);
    }

    public int getColour()
    {
        return colour;
    }

    public void setColour(int colour)
    {
        this.colour = colour;

        initialize();
        invalidate();
    }

    public void setVars(float x1, float y1, float x2, float y2)
    {
        // When the vars changes, the path needs to be updated.
        // In order to make clipping easier, we draw lines from [x0, y0] to
        // [x0, getHeight] and [x3, y3] to [x3, getHeight].
        // This makes the fill section of the path everything below the path.

        path = new Path();

        float cx = getWidth() / 2;
        float cy = getHeight() / 2;

        this.x0 = 0;
        this.y0 = cy + y1;
        this.x1 = x1;
        this.y1 = cy + y1;
        this.x2 = x2;
        this.y2 = cy + y2;
        this.x3 = getWidth();
        this.y3 = cy + y2;

        // Move to bottom, draw up
        path.moveTo(this.x0, getHeight());
        path.lineTo(this.x0 - paintLine.getStrokeMiter(), this.y0);

        path.cubicTo(this.x1, this.y1, this.x2, this.y2, this.x3, this.y3);

        // Draw down
        path.lineTo(this.x3 + paintLine.getStrokeMiter(), getHeight());

        invalidate();
    }

    @Override
    public void draw(Canvas canvas)
    {
        super.draw(canvas);

        if (path != null && paintFill != null)
        {
            // Draw gradient background first, and then clip the irrelevant section away.
            // This will let our gradient be uniform irrespective of the vars used.
            canvas.drawRect(x0, 0, x3, getHeight(), paintFill);

            canvas.save();
            canvas.clipPath(path, Region.Op.DIFFERENCE);
            canvas.drawRect(x0, 0, x3, getHeight(), paintClear);
            canvas.restore();

            canvas.drawPath(path, paintLine);
        }
    }
}

enter