Android 虛線實現繪製 - DashPathEffect

前言:

通過view繪製虛實線,採用Android自帶API——DashPathEffect。具體使用請參考更多的鏈接,這裏只是講解。

構造函數

DashPathEffect 的構造函數有兩個參數:

DashPathEffect (float[] intervals, float phase)

官方文檔解釋如下:

The intervals array must contain an even number of entries (>=2), with the even indices specifying the "on" intervals, and the odd indices specifying the "off" intervals. phase is an offset into the intervals array (mod the sum of all of the intervals). The intervals array controls the length of the dashes. The paint's strokeWidth controls the thickness of the dashes. Note: this path effect only affects drawing with the paint's style is set to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with style == FILL.

翻譯成中文如下:

間隔數組必須包含偶數個條目(大於等於2),偶數索引指定“開”間隔,而奇數索引指定“關”間隔。相位是間隔數組的偏移量(所有間隔的總和)。間隔數組控制了衝線的長度。畫筆寬度寬度控制着衝線的厚度。注意:路徑效果只對畫筆樣式爲描邊或填充和描邊有效。如果畫筆樣式爲填充則會忽略它。

下面通過一個示例來研究這兩個參數的作用。

代碼部分

  • MainActivity.java
package ivan.rich.patheffect;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

 

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ivan.rich.patheffect.MainActivity">

    <ivan.rich.patheffect.PathEffectView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
  • PathEffectView.java
package ivan.rich.patheffect;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

public class PathEffectView extends View {

    private int mWidth;
    private int mHeight;

    private Paint mLinePaint;
    private Paint mPaint;
    private Path mPath;

    public PathEffectView(Context context) {
        this(context, null);
    }

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

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(20);
        mPaint.setColor(getResources().getColor(R.color.colorPrimary));
        mPaint.setStyle(Paint.Style.STROKE);

        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setStrokeWidth(1);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setColor(getResources().getColor(R.color.colorAccent));

        mPath = new Path();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 繪製一條參考線
        canvas.drawLine(60, 0, 60, mHeight, mLinePaint);

        // 繪製第一條虛線
        DashPathEffect dashPathEffect1 = new DashPathEffect(new float[]{60, 60}, 0);
        mPaint.setPathEffect(dashPathEffect1);
        mPath.reset();
        mPath.moveTo(0, mHeight / 10);
        mPath.lineTo(mWidth, mHeight / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第二條虛線
        DashPathEffect dashPathEffect2 = new DashPathEffect(new float[]{60, 60}, 20);
        mPaint.setPathEffect(dashPathEffect2);
        mPath.reset();
        mPath.moveTo(0, mHeight * 2 / 10);
        mPath.lineTo(mWidth, mHeight * 2 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第三條虛線
        DashPathEffect dashPathEffect3 = new DashPathEffect(new float[]{60, 60}, 40);
        mPaint.setPathEffect(dashPathEffect3);
        mPath.reset();
        mPath.moveTo(0, mHeight * 3 / 10);
        mPath.lineTo(mWidth, mHeight * 3 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第四條虛線
        DashPathEffect dashPathEffect4 = new DashPathEffect(new float[]{60, 60}, 60);
        mPaint.setPathEffect(dashPathEffect4);
        mPath.reset();
        mPath.moveTo(0, mHeight * 4 / 10);
        mPath.lineTo(mWidth, mHeight * 4 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第五條虛線
        DashPathEffect dashPathEffect5 = new DashPathEffect(new float[]{60, 60, 30, 30}, 0);
        mPaint.setPathEffect(dashPathEffect5);
        mPath.reset();
        mPath.moveTo(0, mHeight * 6 / 10);
        mPath.lineTo(mWidth, mHeight * 6 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第六條虛線
        DashPathEffect dashPathEffect6 = new DashPathEffect(new float[]{60, 30, 30, 60}, 0);
        mPaint.setPathEffect(dashPathEffect6);
        mPath.reset();
        mPath.moveTo(0, mHeight * 7 / 10);
        mPath.lineTo(mWidth, mHeight * 7 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第七條虛線
        DashPathEffect dashPathEffect7 = new DashPathEffect(new float[]{30, 60, 60, 30}, 0);
        mPaint.setPathEffect(dashPathEffect7);
        mPath.reset();
        mPath.moveTo(0, mHeight * 8 / 10);
        mPath.lineTo(mWidth, mHeight * 8 / 10);
        canvas.drawPath(mPath, mPaint);

        // 繪製第八條虛線
        DashPathEffect dashPathEffect8 = new DashPathEffect(new float[]{30, 30, 60, 60}, 0);
        mPaint.setPathEffect(dashPathEffect8);
        mPath.reset();
        mPath.moveTo(0, mHeight * 9 / 10);
        mPath.lineTo(mWidth, mHeight * 9 / 10);
        canvas.drawPath(mPath, mPaint);
    }
}

運行結果

參數分析

1.首先看截圖上半部分的四條虛線段,四條虛線對應的DashPathEffect如下:

DashPathEffect dashPathEffect1 = new DashPathEffect(new float[]{60, 60}, 0);
DashPathEffect dashPathEffect2 = new DashPathEffect(new float[]{60, 60}, 20);
DashPathEffect dashPathEffect3 = new DashPathEffect(new float[]{60, 60}, 40);
DashPathEffect dashPathEffect4 = new DashPathEffect(new float[]{60, 60}, 60);

這四個DashPathEffect的區別在於第二個參數phase值不同,以參考線爲基準可以清晰地看到phase參數的作用是將整個View向“左”移動phase。什麼意思呢,左移爲0:不移動;左移爲20:移動20個單位長度;左移爲40:移動40個單位長度。因此,左移60的時候,第四根線條相對第一根線條,左移了一個實線段。

2.然後看截圖下半部分的四條虛線段,這四條虛線段對應的DashPathEffect如下:

DashPathEffect dashPathEffect5 = new DashPathEffect(new float[]{60, 60, 30, 30}, 0);
DashPathEffect dashPathEffect6 = new DashPathEffect(new float[]{60, 30, 30, 60}, 0);
DashPathEffect dashPathEffect7 = new DashPathEffect(new float[]{30, 60, 60, 30}, 0);
DashPathEffect dashPathEffect8 = new DashPathEffect(new float[]{60, 60, 40, 40, 20, 20}, 0);

從效果圖可以看出間隔數組的偶數索引處數組值對應的是實線寬度,奇數索引處數組值對應的是實線之後空白線的寬度。前面已經提到過數組必須包含偶數個條目,所以“on”和“off”值是對應的。在繪製View時系統遍歷當前間隔數組,依次繪製第一個“on”和第一個“off”值,第二個“on”和第二個“off"值。。。,照此類推直至繪製完所有對應的"on"和"off”值,然後按照此方法循環遍歷間隔數組直至View的繪製完成。用代碼概括來說就是:

for (i=0 ; i<intervals.length; i+=2) {
    // 實線寬度on
    mLineWidth = intervals[i];
    // 實線之間空白線寬度off
    mBlankSpace = intervals[i+1];
}

總結

構造函數

DashPathEffect(float intervals[], float phase)

參數含義

  • intervals: 控制實線和實線之後空白線的寬度(數組長度必須爲偶數)
  • phase: 將View向”左“偏移phase

用法

Paint.setPathEffect(DashPathEffect dashPathEffect);
發佈了81 篇原創文章 · 獲贊 15 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章