自定义Drawable,绘制圆形、正三角形、二阶贝塞尔曲线、梯形等。
圆形
// 画圆
PointF point = new PointF(radius, radius);
canvas.drawCircle(point.x, point.y, radius, mPaint);
正三角
// 画正三角
PointF trianglePoint1 = new PointF(radius, radius*2);
PointF trianglePoint2 = calculatePoint(trianglePoint1, radius*2, -60);
PointF trianglePoint3 = calculatePoint(trianglePoint1, radius*2, -120);
Path mPath = new Path();
mPath.reset();
mPath.moveTo(trianglePoint1.x, trianglePoint1.y);
mPath.lineTo(trianglePoint2.x, trianglePoint2.y);
mPath.lineTo(trianglePoint3.x, trianglePoint3.y);
canvas.drawPath(mPath, mPaint);
梯形
// 画梯形
PointF trapezoidTopMiddlePoint = new PointF(radius*4, radius/2);
PointF trapezoidPoint1 = calculatePoint(trapezoidTopMiddlePoint, radius/2, 0);
PointF trapezoidPoint2 = calculatePoint(trapezoidTopMiddlePoint, radius/2, -180);
PointF trapezoidBottomMiddlePoint = new PointF(radius*4, radius*1.6F);
PointF trapezoidPoint3 = calculatePoint(trapezoidBottomMiddlePoint, radius, 0);
PointF trapezoidPoint4 = calculatePoint(trapezoidBottomMiddlePoint, radius, -180);
mPath.reset();
mPath.moveTo(trapezoidPoint1.x, trapezoidPoint1.y);
mPath.lineTo(trapezoidPoint2.x, trapezoidPoint2.y);
mPath.lineTo(trapezoidPoint4.x, trapezoidPoint4.y);
mPath.lineTo(trapezoidPoint3.x, trapezoidPoint3.y);
canvas.drawPath(mPath, mPaint);
二阶贝塞尔曲线
// 二阶贝塞尔曲线
PointF bezierStartPoint = new PointF(radius*2, radius*2);
PointF bezierEndPoint = new PointF(radius*4, radius*2);
PointF controlPoint = new PointF(radius*6f, radius*6f);
mPath.reset();
mPath.moveTo(bezierStartPoint.x, bezierStartPoint.y);
mPath.quadTo(controlPoint.x, controlPoint.y, bezierEndPoint.x, bezierEndPoint.y);
canvas.drawPath(mPath, mPaint);
根据起点、角度、长度,计算终点位置
public PointF calculatePoint(PointF point, float length, float angle){
float x = (float) (Math.cos(Math.toRadians(angle)) * length);
float y = (float) (Math.sin(Math.toRadians(angle-180)) * length);
return new PointF(point.x+x, point.y + y);
}
Math.toRadians:将角度转成弧度
效果图
自定义Drawable完整代码:GitHub
public class TestDrawable extends Drawable {
private Paint mPaint;
// 半径
float radius = 200;
public TestDrawable(){
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setARGB(100, 244, 92, 71);
}
@Override
public void draw(@NonNull Canvas canvas) {
// 画圆
PointF point = new PointF(radius, radius);
canvas.drawCircle(point.x, point.y, radius, mPaint);
// 画正三角
PointF trianglePoint1 = new PointF(radius, radius*2);
PointF trianglePoint2 = calculatePoint(trianglePoint1, radius*2, -60);
PointF trianglePoint3 = calculatePoint(trianglePoint1, radius*2, -120);
Path mPath = new Path();
mPath.reset();
mPath.moveTo(trianglePoint1.x, trianglePoint1.y);
mPath.lineTo(trianglePoint2.x, trianglePoint2.y);
mPath.lineTo(trianglePoint3.x, trianglePoint3.y);
canvas.drawPath(mPath, mPaint);
// 画梯形
PointF trapezoidTopMiddlePoint = new PointF(radius*4, radius/2);
PointF trapezoidPoint1 = calculatePoint(trapezoidTopMiddlePoint, radius/2, 0);
PointF trapezoidPoint2 = calculatePoint(trapezoidTopMiddlePoint, radius/2, -180);
PointF trapezoidBottomMiddlePoint = new PointF(radius*4, radius*1.6F);
PointF trapezoidPoint3 = calculatePoint(trapezoidBottomMiddlePoint, radius, 0);
PointF trapezoidPoint4 = calculatePoint(trapezoidBottomMiddlePoint, radius, -180);
mPath.reset();
mPath.moveTo(trapezoidPoint1.x, trapezoidPoint1.y);
mPath.lineTo(trapezoidPoint2.x, trapezoidPoint2.y);
mPath.lineTo(trapezoidPoint4.x, trapezoidPoint4.y);
mPath.lineTo(trapezoidPoint3.x, trapezoidPoint3.y);
canvas.drawPath(mPath, mPaint);
// 二阶贝塞尔曲线
PointF bezierStartPoint = new PointF(radius*2, radius*2);
PointF bezierEndPoint = new PointF(radius*4, radius*2);
PointF controlPoint = new PointF(radius*6f, radius*6f);
mPath.reset();
mPath.moveTo(bezierStartPoint.x, bezierStartPoint.y);
mPath.quadTo(controlPoint.x, controlPoint.y, bezierEndPoint.x, bezierEndPoint.y);
canvas.drawPath(mPath, mPaint);
}
public PointF calculatePoint(PointF point, float length, float angle){
float x = (float) (Math.cos(Math.toRadians(angle)) * length);
float y = (float) (Math.sin(Math.toRadians(angle-180)) * length);
return new PointF(point.x+x, point.y + y);
}
@Override
public void setAlpha(int i) {
mPaint.setAlpha(i);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicHeight() {
// return super.getIntrinsicHeight();
return (int)(6 * radius);
}
@Override
public int getIntrinsicWidth() {
return super.getIntrinsicWidth();
}
}
setAlpha
设置Drawable的透明度
setColor() 的助手,它只分配颜色的 alpha 值,保持其 r,g,b 值不变。 如果 alpha 值超出范围 [0…255],则结果未定义
setColorFilter
设置或清除paint的颜色过滤器,返回参数。
getOpacity
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
可以根据setAlpha中设置的值进行调整
alpha 为0,设置PixelFormat.TRANSPARENT;
alpha 为255,设置PixelFormat.OPAQUE;
alpha为其它值,设置PixelFormat.TRANSLUCENT;
PixelFormat | 描述 |
---|---|
OPAQUE | 完全不透明,覆盖它下面的所有内容 |
TRANSLUCENT | 完全透明,完全不显示任何东西 |
TRANSLUCENT | 只有绘制的地方,才会覆盖下面的内容 |
path
Path封装了由直线和曲线(二次,三次贝塞尔曲线)构成的几何路径。
注意:用drawPath绘制了后,Path的路径还是存在的,所以如果需要绘制新的路径,需要先调用Path的reset方法。
getIntrinsicHeight、getIntrinsicWidth
view使用了wrap_content时,设置固定的高度/宽度,默认为-1
练习绘制小鱼鱼
源码地址:DrawableTest
效果图:
日进一步!持续努力!