Paint的setStrokeCap、setStrokeJoin、setPathEffect

轉載請以鏈接形式標明出處:
本文出自:103style的博客


setStrokeCap

設置畫筆的線冒樣式:

  • Paint.Cap.BUTT:無
  • Paint.Cap.SQUARE:方形
  • Paint.Cap.ROUND: 半圓形

注意: Paint.Cap.ROUNDPaint.Cap.SQUARE 會在線長度的基礎上首尾添加一個通過 setStrokeWidth 設置的寬度。

示例如下:依次爲 無設置Paint.Cap.BUTTPaint.Cap.SQUAREPaint.Cap.ROUND
可以看到 ROUNDSQUARE 樣式的明顯長一點。

public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(60);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    canvas.drawLine(temp, temp, getMeasuredWidth() - temp, temp, paint);
    paint.setStrokeCap(Paint.Cap.BUTT);
    canvas.drawLine(temp, temp * 2, getMeasuredWidth() - temp, temp * 2, paint);
    paint.setStrokeCap(Paint.Cap.SQUARE);
    canvas.drawLine(temp, temp * 3, getMeasuredWidth() - temp, temp * 3, paint);
    paint.setStrokeCap(Paint.Cap.ROUND);
    canvas.drawLine(temp, temp * 4, getMeasuredWidth() - temp, temp * 4, paint);
}

setStrokeCap

自定義進度條時,就可以直接畫線了。


setStrokeJoin

設置多次調用 Path.lineTo 這種線段之間連接處的樣式。

  • Paint.Join.MITER: 直角的樣式
  • Paint.Join.ROUND:圓弧
  • Paint.Join.BEVEL:在直角樣式上切了一個小三角形

示例如下:

public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(60);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    paint.setStrokeJoin(Paint.Join.MITER);
//    paint.setStrokeJoin(Paint.Join.ROUND);
//    paint.setStrokeJoin(Paint.Join.BEVEL);
    path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    path.moveTo(temp, temp);
    path.lineTo(getMeasuredWidth() - temp, temp);
    path.lineTo(getMeasuredWidth() - temp, getMeasuredHeight() / 2);
    path.lineTo(temp, getMeasuredHeight() / 2);
    path.lineTo(temp, getMeasuredHeight() - temp);
    path.lineTo(getMeasuredWidth() - temp, getMeasuredHeight() - temp);
    canvas.drawPath(path, paint);
}

注意拐角處:

Paint.Join.MITERPaint.Join.MITER
Paint.Join.ROUNDPaint.Join.ROUND
Paint.Join.BEVELPaint.Join.BEVEL


setPathEffect

系統給我們提供了六種效果,分別是 CornerPathEffectDashPathEffectDiscretePathEffectPathDashPathEffectComposePathEffectSumPathEffect。下面我們來一一介紹。
系統提供的六種PathEffect

CornerPathEffect

CornerPathEffect 的作用就是將原來的直線拐角變成圓形拐角,構造函數傳入的就是拐角的半徑。

/**
 * @param radius 拐角處弧度半徑
 */
public CornerPathEffect(float radius) {}

摘自 https://blog.csdn.net/harvic880925/article/details/51010839

示例:

    PathEffect pathEffect;
    public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        paint.setStrokeWidth(30);
        paint.setStyle(Paint.Style.STROKE);
        paint.setDither(true);
        paint.setColor(Color.RED);
        path = new Path();
        pathEffect = new CornerPathEffect(50);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int temp = 120;
        path.moveTo(temp, temp);
        path.lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
        path.lineTo(getMeasuredWidth() - temp, temp);
        paint.setPathEffect(pathEffect);
        canvas.drawPath(path, paint);
}

效果圖:CornerPathEffect


DashPathEffect

DashPathEffect 的作用就是實現 虛線效果。

/**
 * @param 分割線的長度變化值數組,必須大於等於2
 * @param phase  偏移大小
 */
public DashPathEffect(float intervals[], float phase) {}

摘自 https://blog.csdn.net/harvic880925/article/details/51010839

示例:

int phase = 0;
PathEffect pathEffect;
public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(10);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    path = new Path();
    float [] f = {20,10};
    pathEffect = new DashPathEffect(f,phase);
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    path.moveTo(temp, temp);
    path.lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
    path.lineTo(getMeasuredWidth() - temp, temp);
    paint.setPathEffect(pathEffect);
    canvas.drawPath(path, paint);
}

效果圖:DashPathEffect

我們可以通過 修改 偏移值的大小來 實現如下效果:

@Override
protected void onDraw(Canvas canvas) {
    ...
    float[] f = {20, 10};
    pathEffect = new DashPathEffect(f, phase);
    paint.setPathEffect(pathEffect);
    canvas.drawPath(path, paint);
    phase += 5;
    postInvalidate();
}

修改偏移值再重繪


DiscretePathEffect

/**
 * @param segmentLength 每段線段長度
 * @param deviation     偏移
 */
public DiscretePathEffect(float segmentLength, float deviation) { }

DiscretePathEffect 就是將原來路徑分隔很多段 segmentLength 長的線段,然後將每條線段隨機偏移 deviation 的位置,deviation 越大,抖動幅度越大,效果圖如下:
摘自 https://blog.csdn.net/harvic880925/article/details/51010839

示例:

public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(10);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    path = new Path();
    pathEffect = new DiscretePathEffect(50, 50);
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    path.moveTo(temp, temp);
    path.lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
    path.lineTo(getMeasuredWidth() - temp, temp);
    paint.setPathEffect(pathEffect);
    canvas.drawPath(path, paint);
}

效果圖:DiscretePathEffect(10,10)

DiscretePathEffect(10,50)


PathDashPathEffect

/**
 * @param shape   印戳的路徑
 * @param advance 每個印戳的距離
 * @param phase   印戳的偏移大小
 * @param style   每個印戳的變化規則
 */
public PathDashPathEffect(Path shape, float advance, float phase, Style style) {}

PathDashPathEffect 就是再原有路徑上用 PathDashPathEffect 構造函數中的 shape 去繪製這條路徑。提供了TRANSLATEROTATEMORPH 這三種樣式,主要區分拐角處。
效果如下:
摘自 https://blog.csdn.net/harvic880925/article/details/51010839

示例:

public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(10);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    path = new Path();
    dashPath = new Path();
    dashPath.addCircle(0, 0, 10, Path.Direction.CCW);
    dashPath.moveTo(20, 0);
    dashPath.lineTo(0, 20);
    dashPath.lineTo(40, 20);
    dashPath.close();
    pathEffect = new PathDashPathEffect(dashPath, 60, 0, PathDashPathEffect.Style.TRANSLATE);
//    pathEffect = new PathDashPathEffect(dashPath, 60, 0, PathDashPathEffect.Style.ROTATE);
//    pathEffect = new PathDashPathEffect(dashPath, 60, 0, PathDashPathEffect.Style.MORPH);
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    path.moveTo(temp, temp);
    path.lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
    path.lineTo(getMeasuredWidth() - temp, temp);
    canvas.drawPath(path, paint);

    canvas.translate(0, 100);
    paint.setPathEffect(pathEffect);
    canvas.drawPath(path, paint);
}

效果圖,主要看拐角處:PathDashPathEffect  PathDashPathEffect.Style.TRANSLATE
PathDashPathEffect  PathDashPathEffect.Style.ROTATE
PathDashPathEffect  PathDashPathEffect.Style.MORPH


SumPathEffect和 ComposePathEffect

這兩個都是用來合併兩個特效的。

/**
 * (e.g. first(path) + second(path))
 */
public SumPathEffect(PathEffect first, PathEffect second) {}
/**
 * (e.g. outer(inner(path))).
 */
public ComposePathEffect(PathEffect outerpe, PathEffect innerpe) {}

SumPathEffect 是分別對原始路徑分別作用第一個特效和第二個特效。然後再將這兩條路徑合併,做爲最終結果。可以理解爲兩個特效集合的並集。
ComposePathEffect 合併兩個特效是有先後順序的,它會先將第二個參數的PathEffect innerpe的特效作用於路徑上,然後再在此加了特效的路徑上作用第二個特效。可以理解爲兩個特效集合的交集。

示例:

public StrokeJoinCapView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    paint = new Paint();
    paint.setStrokeWidth(10);
    paint.setStyle(Paint.Style.STROKE);
    paint.setDither(true);
    paint.setColor(Color.RED);
    path = new Path();
    pathEffect1 = new DiscretePathEffect(10, 10);
    float[] f = {20, 10};
    pathEffect2 = new DashPathEffect(f, 10);
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int temp = 120;
    path.moveTo(temp, temp);
    path.lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
    path.lineTo(getMeasuredWidth() - temp, temp);
    canvas.drawPath(path, paint);

    canvas.translate(0, 100);
    paint.setPathEffect(new SumPathEffect(pathEffect1, pathEffect2));
    canvas.drawPath(path, paint);

    canvas.translate(0, 200);
    paint.setPathEffect(new ComposePathEffect(pathEffect1, pathEffect2));
    canvas.drawPath(path, paint);
}

效果圖:SumPathEffect 和 ComposePathEffect


參考文章


如果覺得不錯的話,請幫忙點個讚唄。

以上


掃描下面的二維碼,關注我的公衆號 Android1024, 點關注,不迷路。
Android1024

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章