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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM