Android神筆之Paint

鋸齒流沙發表於2018-01-08

再Android中,自定義控制元件是一個非常重要的知識點,而自定義控制元件對Android開發者是一個難點,考驗開發人員對View原理的理解,對於繼承View的自定義控制元件,一般都需要重寫onDraw方法,而且往往需要開發人員能夠掌握Paint這個類。

簡介

The Paint class holds the style and color information about how to draw geometries, text and bitmaps.

Paint:該類儲存了繪製幾何圖形、文字和點陣圖的樣式和顏色資訊。也就是說我們可以使用Paint儲存的樣式和顏色,來繪製圖形、文字和bitmap,這就是Paint的強大之處。接下來我們使用Paint來繪圖,並且看看該類有哪些樣式和顏色。

Paint的使用

使用Paint之前需要初始化

mPaint = new Paint();

設定筆(Paint)的顏色和alpha值:

mPaint.setColor(Color.BLUE);
mPaint.setAlpha(255);
複製程式碼

注意alpha的範圍是[0..255],而不是[0..1],是一個int值。

設定畫筆的樣式:通過mPaint.setStyle()來設定樣式。

    public enum Style {
        /**
         * Geometry and text drawn with this style will be filled, ignoring all
         * stroke-related settings in the paint.
         */
        FILL            (0),
        /**
         * Geometry and text drawn with this style will be stroked, respecting
         * the stroke-related fields on the paint.
         */
        STROKE          (1),
        /**
         * Geometry and text drawn with this style will be both filled and
         * stroked at the same time, respecting the stroke-related fields on
         * the paint. This mode can give unexpected results if the geometry
         * is oriented counter-clockwise. This restriction does not apply to
         * either FILL or STROKE.
         */
        FILL_AND_STROKE (2);

        Style(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }
複製程式碼

總共有三種畫筆的樣式

FILL:填充內容;

STROKE:描邊;

FILL_AND_STROKE:填充內容並描邊。

設定畫筆的寬度

mPaint.setStrokeWidth(50);

設定畫筆的線帽

通過mPaint.setStrokeCap來設定線帽,總共有三種線帽

    /**
     * The Cap specifies the treatment for the beginning and ending of
     * stroked lines and paths. The default is BUTT.
     */
    public enum Cap {
        /**
         * The stroke ends with the path, and does not project beyond it.
         */
        BUTT    (0),
        /**
         * The stroke projects out as a semicircle, with the center at the
         * end of the path.
         */
        ROUND   (1),
        /**
         * The stroke projects out as a square, with the center at the end
         * of the path.
         */
        SQUARE  (2);

        private Cap(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }
複製程式碼

BUTT:沒有線帽,預設模式

ROUND:圓形

SQUARE:方形

三種線帽對比:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.BLUE);
        mPaint.setAlpha(255);

        //設定畫筆的樣式
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        //畫筆的寬度
		mPaint.setStrokeWidth(50);
		mPaint.setStrokeCap(Paint.Cap.SQUARE);//方形
		mPaint.setStrokeJoin(Paint.Join.BEVEL);//直線

        Path path = new Path();
        path.moveTo(100, 100);
        path.lineTo(300, 100);
        canvas.drawPath(path, mPaint);

        mPaint.reset();//重置
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.ROUND);//圓形
        mPaint.setStrokeJoin(Paint.Join.BEVEL);//直線

        Path path1 = new Path();
        path1.moveTo(100, 200);
        path1.lineTo(300, 200);
        canvas.drawPath(path1, mPaint);

        mPaint.reset();//重置
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.BUTT);//沒有
        mPaint.setStrokeJoin(Paint.Join.BEVEL);//直線

        Path path2 = new Path();
        path2.moveTo(100, 300);
        path2.lineTo(300, 300);
        canvas.drawPath(path2, mPaint);

    }
複製程式碼

上面程式碼中有個重置畫筆,這時候需要重新設定畫筆。

線帽對比

設定Join

使用setStrokeJoin方法來設定Join,Join有三種型別:

BEVEL:直線

ROUND:圓角

MITER:銳角

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.BLUE);
        mPaint.setAlpha(255);
        mPaint.setStyle(Paint.Style.STROKE);//設定畫筆的樣式
		mPaint.setStrokeWidth(50);//畫筆的寬度
		mPaint.setStrokeCap(Paint.Cap.BUTT);//線帽
		mPaint.setStrokeJoin(Paint.Join.BEVEL);

        Path path = new Path();
        path.moveTo(100, 100);
		path.lineTo(300, 100);
		path.lineTo(100, 300);
        path.close();
        canvas.drawPath(path, mPaint);

        mPaint.reset();//重置
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.BUTT);//圓形
        mPaint.setStrokeJoin(Paint.Join.ROUND);//圓弧

        Path path1 = new Path();
        path1.moveTo(100, 400);
        path1.lineTo(300, 400);
        path1.lineTo(100, 700);
        path1.close();
        canvas.drawPath(path1, mPaint);

        mPaint.reset();//重置
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.BUTT);//沒有
        mPaint.setStrokeJoin(Paint.Join.MITER);//銳角

        Path path2 = new Path();
        path2.moveTo(100, 800);
        path2.lineTo(300, 800);
        path2.lineTo(100, 1100);
        path2.close();
        canvas.drawPath(path2, mPaint);

    }
複製程式碼

Join對比

以上就是Join三種型別對比。

設定防鋸齒

mPaint.setAntiAlias(true);

如果設定防鋸齒,會損失一定的效能

抖動處理

使用mPaint.setDither()方法,設定是否使用影象抖動處理。會使繪製的圖片等顏色更加的清晰以及飽滿,也是損失效能。

使用Path繪製圖形

Path繪製圖形

點組成線,線組成面,這樣Path可以繪製各種各樣的圖形,可以說是無所不能的了,但是Path也提供了很多方法,來繪製圖形。

文字繪製

上文中,介紹了Paint畫筆,和繪製了一些圖形。但是介紹Paint的時候,我們知道它可以繪製圖形,文字和bitmap,所以Paint是非常強大的了,我們看下Paint是如何繪製文字的。

設定字元之間的間距

setLetterSpacing

設定文字刪除線

mPaint.setStrikeThruText(true);

是否設定下劃線

mPaint.setUnderlineText(true);

設定文字大小

mPaint.setTextSize(textSize);

設定字型型別

mPaint.setTypeface(Typeface.BOLD); // Style public static final int NORMAL = 0;//常規 public static final int BOLD = 1;//粗體 public static final int ITALIC = 2; //斜體 public static final int BOLD_ITALIC = 3;//粗斜體

字型型別有以上四種型別可以設定。

載入自定義字型

Typeface.create(familyName, style)

文字傾斜

mPaint.setTextSkewX(-0.25f);

文字傾斜預設為0,官方推薦的-0.25f是斜體

文字對齊方式

mPaint.setTextAlign(Align.LEFT)

有三種:

public enum Align {
        /**
         * The text is drawn to the right of the x,y origin
         */
        LEFT    (0),//左對齊
        /**
         * The text is drawn centered horizontally on the x,y origin
         */
        CENTER  (1),//居中
        /**
         * The text is drawn to the left of the x,y origin
         */
        RIGHT   (2);//右對齊

        private Align(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }
複製程式碼

計算制定長度的字串

int breadText = mPaint.breakText(text, measureForwards, maxWidth, measuredWidth)

注意:字元長度、字元個數、顯示的時候是真實的長度

Rect bounds獲取文字的矩形區域(寬高)
mPaint.getTextBounds(text, index, count, bounds)
mPaint.getTextBounds(text, start, end, bounds)
		
//獲取文字的寬度,和上面類似,但是是一個比較粗略的結果
float measureText = mPaint.measureText(str);
//獲取文字的寬度,和上面類似,但是是比較精準的。
float[] measuredWidth = new float[10];

//measuredWidth得到每一個字元的寬度;textWidths字元數
int textWidths = mPaint.getTextWidths(str, measuredWidth);
mPaint.getTextWidths(text, start, end, widths)
複製程式碼

使用drawText繪製文字

public class PaintView extends View {

    private Paint mPaint;
    private String text = "你是我世界之光,我心另一半";

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

    public PaintView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        mPaint = new Paint();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.BLUE);
        mPaint.setStyle(Paint.Style.STROKE);//設定畫筆的樣式
		mPaint.setStrokeCap(Paint.Cap.BUTT);//線帽
		mPaint.setStrokeJoin(Paint.Join.BEVEL);

        int top = 100;
        int baselineX = 0;
        mPaint.setTextSize(50);
        mPaint.setTextAlign(Paint.Align.LEFT);

        canvas.drawLine(0, top, 2000, top, mPaint);


        //文字Metrics
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        float baselineY = top - fontMetrics.top;
        canvas.drawText(text, baselineX, baselineY, mPaint);

    }
}
複製程式碼

繪製文字

繪製文字時,還有一個很重要的知識點就是基線的確定,有關drawtext的基線,可以參考《DrawText 基線的確定》這篇文章。

相關文章