天天看點

Android自定義View之畫筆與畫布

在這裡邊有三個對象非常重要

Paint畫筆 Canvas畫布 Path路徑 不多說了 代碼撸起來

1.Paint畫筆和Canvas畫布

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

/**Paint畫筆  Canvas畫布
 * Created by xuenan on 2016/7/14.
 */
public class MyView1 extends View{
    private Paint linePaint;
    public MyView1(Context context) {
        super(context);
        linePaint = new Paint();//初始化畫筆
        //設定是否抗鋸齒;設定抗鋸齒會使圖像邊緣更清晰一些,鋸齒痕迹不會那麼明顯。
        linePaint.setAntiAlias(true);
        //設定填充樣式
        //Paint.Style 類型:
        //Paint.Style.FILL_AND_STROKE 填充且描邊
        //Paint.Style.STROKE 描邊
        //Paint.Style.FILL 填充
        linePaint.setStyle(Paint.Style.STROKE);
        //設定畫筆顔色
        linePaint.setColor(Color.GREEN);
        //設定畫筆寬度
        linePaint.setStrokeWidth();
        //setShadowLayer(float radius, float dx, float dy, int shadowColor) 設定陰影
        //radius : 表示陰影的傾斜度
        //dx : 水準位移
        //dy : 垂直位移
        //shadowColor : 陰影顔色
        //這個方法不支援硬體加速,是以我們要測試時必須先關閉硬體加速。
        //加上setLayerType(LAYER_TYPE_SOFTWARE, null); 并且確定你的最小api8以上。
        //linePaint.setShadowLayer(10,15,15,Color.RED);

    }
    //
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //這兩個功能一樣,都是用來設定背景顔色的。
        canvas.drawColor(Color.parseColor("#F5FFFA"));
        //canvas.drawRGB(255, 255, 0);
        //1直線繪制
        //drawLine(float startX, float startY, float stopX, float stopY,@NonNull Paint paint)
        //startX : 開始點X坐标
        //startY : 開始點Y坐标
        //stopX : 結束點X坐标
        //stopY : 結束點Y坐标
        //canvas.drawLine(100,100,600,600,linePaint);

        //2多條直線
        //drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint)
        //drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint)
        //pts : 是點的集合且大小最小為4而且是2的倍數。表示每2個點連接配接形成一條直線,pts 的組織方式為{x1,y1,x2,y2….}
        //offset : 集合中跳過的數值個數,注意不是點的個數!一個點是兩個數值
        //count : 參與繪制的數值的個數,指pts[]裡數值個數,而不是點的個數,因為一個點是兩個數值
        float [] pts={,,,,,,,};
        //點(50,50)和點(200,200)連接配接成一條直線;點(400,400)和點(600,600)連接配接成直線。
        //canvas.drawLines(pts,linePaint);
        //表示從第二個50開始連續的4個點(50,200,200,400)連接配接的直線
        //canvas.drawLines(pts,1,4,linePaint);

        //3 點即多個點
        //drawPoint(float x, float y, @NonNull Paint paint)
        //canvas.drawPoint(10,10,linePaint);//一個點
        //drawPoints(@Size(multiple=2) @NonNull float[] pts, @NonNull Paint paint)
        //drawPoints(@Size(multiple=2) float[] pts, int offset, int count,@NonNull Paint paint)
        //canvas.drawPoints(pts,linePaint);//多個點

        //4矩形  差別RectF 與Rect ,RectF坐标系是浮點型;Rect坐标系是整形。
        //drawRect(@NonNull RectF rect, @NonNull Paint paint)
        //drawRect(@NonNull Rect r, @NonNull Paint paint)
        //drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
        //left  指定矩形框左上角的x坐标
        //top: 指定矩形框左上角的y坐标
        //right 指定矩形框右下角的x坐标
        //bottom指定矩形框右下角的y坐标
        //canvas.drawRect(new Rect(20,20,300,200),linePaint);
        //canvas.drawRect(new RectF(20,20,300,200),linePaint);
        //canvas.drawRect(20,20,300,200,linePaint);

        //5圓角矩形
        //RectF: 繪制的矩形
        //rx : 生成圓角的橢圓X軸半徑
        //ry : 生成圓角的橢圓Y軸的半徑
        //drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)
        //drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,@NonNull Paint paint)
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             //這個方法有點坑啊 隻能在5.0以上使用,推薦使用下邊的方法代替
        //    canvas.drawRoundRect(200,200,1000,800,15,15,linePaint);
        //}
        //canvas.drawRoundRect(new RectF(200,200,1000,800),15,15,linePaint);

        //6圓形
        //drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
        //cx : 圓心X坐标
        //cy : 圓心Y坐标
        //radius : 半徑
        //canvas.drawCircle(900,900,500,linePaint);

        //7橢圓 參數為橢圓的矩形邊界
        //drawOval(@NonNull RectF oval, @NonNull Paint paint)
        //drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)
        //canvas.drawOval(new RectF(200,200,1000,800),linePaint);
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        //    canvas.drawOval(200,200,1000,800,linePaint);
        //}

        //8 圓弧
        //oval : 生成橢圓的矩形
        //startAngle : 弧開始的角度 (X軸正方向為0度,順時針弧度增大)
        //sweepAngle : 繪制多少弧度 (注意不是結束弧度)
        //useCenter : 是否有弧的兩邊 true有兩邊 false無兩邊
        //drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)
        //drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint)
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        //   canvas.drawArc(100,100,800,600,0,90,true,linePaint);
        //}
        //canvas.drawArc(new RectF(100,100,800,600),0,90,true,linePaint);


    }
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

2.Path路徑 為了直覺 我加上了網格

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;

/**Paint畫筆  Canvas畫布 Path 路徑
 * Created by xuenan on 2016/7/14.
 */
/**Path的方法
 *moveTo    移動起點    移動下一次操作的起點位置
 *lineTo    連接配接直線    連接配接上一個點到目前點之間的直線
 *setLastPoint  設定終點    重置最後一個點的位置
 *close     閉合路勁    從最後一個點連接配接最初的一個點,形成一個閉合區域
 *addRect   添加矩形    添加矩形到目前Path
 *addRoundRect  添加圓角矩形  添加圓角矩形到目前Path
 *addOval   添加橢圓    添加橢圓到目前Path
 *addCircle     添加圓     添加圓到目前Path
 *addPah    添加路勁    添加路勁到目前Path
 *addArc    添加圓弧    添加圓弧到目前Path
 *arcTo     圓弧  繪制圓弧,注意和addArc的差別
 *isEmpty   是否為空    判定Path是否為空
 *isRect    是否為矩形   判定Path是否是一個矩形
 *set   替換路勁    用新的路勁替換目前路勁的所有内容
 *offset    偏移路勁    對目前的路勁進行偏移
 *quadTo    貝塞爾曲線   二次貝塞爾曲線的方法
 *cubicTo   貝塞爾曲線   三次貝塞爾曲線的方法
 *rMoveTo,rlineTo,rQuadTo,rCubicTo  rXxx方法  不帶r的方法是基于原點坐标系(偏移量),帶r的基于目前點坐标系(偏移量)
 *op    布爾操作    對兩個Path進行布爾運算(交集,并集)等操作
 *setFillType   填充模式    設定Path的填充模式
 *getFillType   填充模式    擷取Path的填充
 *isInverseFillType     是否逆填充   判斷是否是逆填充模式
 *toggleInverseFillType     相反模式    切換相反的填充模式
 *getFillType   填充模式    擷取Path的填充
 *incReserve    提示方法    提示Path還有多少個點等待加入
 *computeBounds     計算邊界    計算Path的路勁
 *reset,rewind  重置路勁    清除Path中的内容(reset相當于new Path , rewind 會保留Path的資料結構)
 *transform     矩陣操作    矩陣變換
 */
public class MyView2 extends View{
    private Paint path_paint;//路徑繪制
    private Paint  paint;  //網格繪圖
    private Context mcontext;
    private int width2,height2;
    public MyView2(Context context) {
        super(context);
        this.mcontext =context;
        WindowManager manager = (WindowManager) mcontext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        width2 = outMetrics.widthPixels;
        height2 = outMetrics.heightPixels;
        path_paint = new Paint();
        path_paint.setAntiAlias(true);
        path_paint.setStyle(Paint.Style.FILL_AND_STROKE);
        path_paint.setStrokeWidth();
        path_paint.setColor(Color.parseColor("#FF0000"));
        //paint.setStyle(Paint.Style.FILL);,設定畫筆為實心。一些線條将在畫布上看不見。

        paint = new Paint();
        paint.setColor(Color.parseColor("#A8A8A8"));
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.parseColor("#F5FFFA"));//畫布的背景
        //網格線的繪制
        final int width = width2;
        final int height = height2;
        final int space = ;   //長寬間隔
        int vertz = ;
        int hortz = ;
        for(int i=;i<;i++){
            canvas.drawLine(,  vertz,  width, vertz, paint);
            canvas.drawLine(hortz, , hortz, height, paint);
            vertz+=space;
            hortz+=space;
        }

        Path path = new Path();
        //1.lineTo  連接配接直線    連接配接上一個點到目前點之間的直線
        //path.lineTo(200,200);
        //path.lineTo(400, 0);

        //2.方法名                作用              是否影響之前的操作    是否影響之後的操作
        //moveTo        移動下一次操作的起點位置          否                   是
        //setLastPoint  改變上一次操作點的位置           是                   是
        //當我們繪制線條之前,調用moveTo 和 setLastPoint效果是一樣的,
        //都是對坐标原點(0,0)進行操作。setLastPoint是重置上一次操作的最後一點
        //path.lineTo(200, 200);
        //path.moveTo(300,300);
        //path.lineTo(400, 0);

        //path.lineTo(200, 200);
        //path.setLastPoint(300,100);
        //path.lineTo(400, 0);

        //3.close方法連接配接最後一個點和最初一個點(如果兩個點不重合)形成一個閉合的圖形。
        //close的作用的封閉路徑,如果連接配接最後一個點和最初一個點任然無法形成閉合的區域,那麼close什麼也不做。
        //path.moveTo(100,100);
        //path.lineTo(500,100);
        //path.lineTo(300,400);
        //path.close();

        //4.二次貝塞爾曲線
        //public void quadTo(float x1, float y1, float x2, float y2)
        //path.moveTo(100, 400);
        //path.quadTo(300, 100, 400, 400);

        //5.三次貝塞爾曲線
        //public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
        //cubicTo方法比quadTo方法多了一個點坐标,那麼其中(x1,y1) 為控制點,(x2,y2)為控制點,(x3,y3) 為結束點。
        //path.moveTo(100, 400);
        //path.cubicTo(100, 400, 300, 100, 400, 400);

        //6.1Path中添加基本圖形以及區分addArc和arcTo
        //圓形
        //addCircle(float x, float y, float radius, Path.Direction dir)
        //橢圓
        //addOval(RectF oval, Path.Direction dir)
        //addOval(float left, float top, float right, float bottom, Path.Direction dir)
        //矩形
        //addRect(RectF rect, Path.Direction dir)
        //addRect(float left, float top, float right, float bottom, Path.Direction dir)
        //圓角矩形
        //addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)
        //addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir)
        //addRoundRect(RectF rect, float[] radii, Path.Direction dir)
        //addRoundRect(float left, float top, float right, float bottom, float[] radii, Path.Direction dir)
        //Direction的意思是方向,指導,趨勢。點進去跟一下你會發現Direction是一個枚舉類型(Enum)
        // 分别有CW(順時針),CCW(逆時針)兩個常量。那麼它的作用主要有以下兩點:
        //1:在添加圖形時确定閉合順序(各個點的記錄順序)
        //:對自相交圖形的渲染結果有影響
        //閉合的問題,相交問題與設定填充模式有關。
        //path.addRect(100, 200, 500, 400, Path.Direction.CCW);
        //path.setLastPoint(400,300);
        //path.addCircle(300,300,200, Path.Direction.CW);

        //6.2addPath路徑合并
        //addPath方法就是将兩個路徑合并到一起。
        //第二個方法的dx,dy指的是偏移量,第三個方法是添加到目前path之前先使用Matrix進行變換
        //public void addPath(Path src)
        //public void addPath(Path src, float dx, float dy)
        //public void addPath(Path src, Matrix matrix)
        //path.addRect(100,100,400,300, Path.Direction.CW);
        //Path src=new Path();
        //src.addCircle(300,300,100, Path.Direction.CW);
        //path.addPath(src,0,100);

        //6.3addArc與arcTo
        //addArc(RectF oval, float startAngle, float sweepAngle)
        //addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle)
        //arcTo(RectF oval, float startAngle, float sweepAngle)
        //arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
        //arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)
        //差別
        //名稱               作用                              差別
        //addArc    添加一個圓弧到Path     直接添加一個圓弧到path中,和上一次操作點無關
        //arcTo     添加一個圓弧到Path     添加一個圓弧到path中,如果圓弧的起點和上次操作點坐标不同就連接配接兩個點
        //startAngle表示開始圓弧度數(0度與X軸方向對齊,順時針移動,弧度增大)。
        //注意:sweepAngle表示運動了多少弧度,并不是結束弧度。
        //forceMoveTo表示“是否強制使用moveTo”,也就是說是否使用moveTo将上一次操作點移動到圓弧的起點坐标。
        // 預設是false。
        //true  将最後一個點移動到圓弧起點,即不連接配接最後一個點與圓弧起點
        //false     不移動,而是連接配接最後一個點與圓弧起點(注意之前沒有操作的話,不會連接配接原點)
        //path.lineTo(200, 200);
        //RectF rectF = new RectF(100, 100, 400, 400);
        //path.arcTo(rectF, 0, 270, true);
        // path.addArc(rectF,0,270);和上面一句等價
        //path.arcTo(rectF, 0, 270, false);

        //6.4 isEmpty、 isRect、 set 和 offset
        //6.4.1 isEmpty判斷path中是否包含内容。path.isEmpty()
        //Log.e("-----", "----" + path.isEmpty());//-----: ----true
        //path.lineTo(100,100);
        //Log.e("-----","----"+path.isEmpty());//-----: ----false
        //6.4.2 isRect 判斷path是否是一個矩形,如果是一個矩形的話,
        // 會将矩形的資訊存放進參數rect中。isRect(RectF rect)
        //RectF rectF = new RectF();
        //rectF.left = 100;
        //rectF.top = 100;
        //rectF.right = 400;
        //rectF.bottom = 300;
        //path.addRect(rectF, Path.Direction.CW);
        //boolean isRect = path.isRect(rectF);
        //Log.e("-----", "------" + isRect);//-----: ------true
        //6.4.3 set public void set(Path src)将新的path指派到現有path。
        // 相當于運算符中的“=”,如a=b,把b指派給a
        //path.addRect(100,100,400,300, Path.Direction.CW);
        //Path src=new Path();
        //src.addCircle(300,200,100, Path.Direction.CW);
        //path.set(src);
        //6.4.4 offset平移
        //public void offset(float dx, float dy)
        //public void offset(float dx, float dy, Path dst)
        //這個方法就是對Path進行一段平移,正方向和X軸,Y軸方向一緻(如果dx為正數則向右平移,
        //反之向左平移;如果dy為正則向下平移,反之向上平移)。我們看到第二個方法多了一個dst,
        //這個又是一個什麼玩意呢,其實參數das是存儲平移後的path的。
        //先看兩個參數的
        //path.addCircle(300, 200, 100, Path.Direction.CW);
        //path.offset(-100, 100);
        //再看三個參數的
        //從運作效果圖可以看出,雖然我們在dst中添加了一個圓形,但是并沒有表現出來,
        //是以,當dst中存在内容時,dst中原有的内容會被清空,而存放平移後的path。
        //也就是說dst=path;即dst.set(path)哎 然并卵的東西
        //path.addCircle(300, 200, 100, Path.Direction.CW);
        //Path dst = new Path();
        //dst.addCircle(500, 200, 200, Path.Direction.CW);
        //path.offset(-100, 100, dst);

        //7 FillType 對兩個參數取交集 并集 補集
        //public void setFillType(Path.FillType ft)
        //public Path.FillType getFillType()
        //setFillType方法中的參數Path.FillType為枚舉類型:
        //FillType.WINDING              取path所有所在區域 預設值
        //FillType.EVEN_ODD             取path所在并不相交區域
        //FillType.INVERSE_WINDING      取path所有未占區域
        //FillType.INVERSE_EVEN_ODD     取path未占或相交區域
        //7.1 WINDING 并集
        //path.addCircle(300,200,100, Path.Direction.CW);
        //path.addCircle(200,200,100, Path.Direction.CW);
        //path.setFillType(Path.FillType.WINDING);
        //7.2 EVEN_ODD
        //path.addCircle(300,200,100, Path.Direction.CW);
        //path.addCircle(200,200,100, Path.Direction.CW);
        //path.setFillType(Path.FillType.EVEN_ODD);
        //7.3 INVERSE_WINDING 補集
        //path.addCircle(300,200,100, Path.Direction.CW);
        //path.addCircle(200,200,100, Path.Direction.CW);
        //path.setFillType(Path.FillType.INVERSE_WINDING);
        //7.4 INVERSE_EVEN_ODD 并集
        path.addCircle(,,, Path.Direction.CW);
        path.addCircle(,,, Path.Direction.CW);
        path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
        path.toggleInverseFillType();


        canvas.drawPath(path, path_paint);
    }
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247

3.文字設計

package com.longlian.paintdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;

/**文字繪制
 * Created by xuenan on 2016/7/15.
 */
/**
 *text_paint.setAntiAlias(true); //指定是否使用抗鋸齒功能  如果使用會使繪圖速度變慢 預設false
 *text_paint.setStyle(Paint.Style.FILL);//繪圖樣式  對于設文字和幾何圖形都有效
 *text_paint.setTextAlign(Paint.Align.LEFT);//設定文字對齊方式  取值:align.CENTER、align.LEFT或align.RIGHT 預設align.LEFT
 *text_paint.setTextSize(12);
 *text_paint.setStrokeWidth(5);//設定畫筆寬度
 *text_paint.setTextSize(80);//設定文字大小
 *樣式設定
 *text_paint.setFakeBoldText(true);//設定是否為粗體文字
 *text_paint.setUnderlineText(true);//設定下劃線
 *text_paint.setTextSkewX((float) -0.25);//設定字型水準傾斜度  普通斜體字是-0.25
 *text_paint.setStrikeThruText(true);//設定帶有删除線效果
 *其它設定
 *text_paint.setTextScaleX(2);//隻會将水準方向拉伸  高度不會變
 *
 **/
public class MyView3 extends View{
    private Paint text_paint;
    private Paint  paint;  //網格繪圖
    private Context mcontext;
    private int width2,height2;
    public MyView3(Context context) {
        super(context);
        this.mcontext =context;
        WindowManager manager = (WindowManager) mcontext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        width2 = outMetrics.widthPixels;
        height2 = outMetrics.heightPixels;
        text_paint = new Paint();
        text_paint.setStrokeWidth();
        text_paint.setTextSize();
        text_paint.setColor(Color.RED);

        paint = new Paint();
        paint.setColor(Color.parseColor("#A8A8A8"));
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.parseColor("#F5FFFA"));//畫布的背景
        //網格線的繪制
        final int width = width2;
        final int height = height2;
        final int space = ;   //長寬間隔
        int vertz = ;
        int hortz = ;
        for(int i=;i<;i++){
            canvas.drawLine(,  vertz,  width, vertz, paint);
            canvas.drawLine(hortz, , hortz, height, paint);
            vertz+=space;
            hortz+=space;
        }
        //1、文本繪圖樣式
        //設定繪圖樣式 為填充
        //text_paint.setStyle(Paint.Style.FILL);
        //canvas.drawText("我是一顆小小的石頭", 100, 100, text_paint);
        //設定繪圖樣式 為描邊
        //text_paint.setStyle(Paint.Style.STROKE);
        //canvas.drawText("我是一顆小小的石頭", 100, 300, text_paint);
        //設定繪圖樣式 為填充且描邊
        //text_paint.setStyle(Paint.Style.FILL_AND_STROKE);
        //canvas.drawText("我是一顆小小的石頭", 100,500, text_paint);

        //2、setTextAlign(Paint.Align align) 文字的對齊方式
        //text_paint.setStyle(Paint.Style.FILL);
        //設定對齊方式  左對齊
        //text_paint.setTextAlign(Paint.Align.LEFT);
        //canvas.drawText("小小的石頭", 500,100, text_paint);//點(500,100)在文本的左邊
        //設定對齊方式  中間對齊
        //text_paint.setTextAlign(Paint.Align.CENTER);
        //canvas.drawText("小小的石頭", 500, 200, text_paint);//點(500,100)在文本的中間
        //設定對齊方式  右對齊
        //text_paint.setTextAlign(Paint.Align.RIGHT);
        //canvas.drawText("小小的石頭", 500,300, text_paint);//點(500,100)在文本的右邊

        //3、文字樣式設定
        //text_paint.setStyle(Paint.Style.FILL);
        //text_paint.setFakeBoldText(true);//是否粗體文字
        //text_paint.setUnderlineText(true);//設定下劃線
        //text_paint.setStrikeThruText(true);//設定删除線效果
        //canvas.drawText("小小的石頭", 200, 200, text_paint);

        //4、文字傾斜度設定
        //可見普通斜體字是-0.25f,大于-0.25f 向左傾斜,小于 -0.25f 向右傾斜。
        //text_paint.setStyle(Paint.Style.FILL);
        //text_paint.setTextSkewX(-0.25f);
        //canvas.drawText("小小的石頭", 100, 100, text_paint);
        //text_paint.setTextSkewX(0.25f);
        //canvas.drawText("小小的石頭", 100, 200, text_paint);
        //text_paint.setTextSkewX(-0.5f);
        //canvas.drawText("小小的石頭", 100, 300, text_paint);

        //5、水準拉伸設定 僅是水準方向拉伸,高度并未改變。
        //text_paint.setStyle(Paint.Style.FILL);
        //text_paint.setTextScaleX(1);//不拉伸
        //canvas.drawText("小小的石頭", 100, 100, text_paint);
        //text_paint.setTextScaleX(2);//水準方向拉伸2倍
        //canvas.drawText("小小的石頭", 100, 200, text_paint);
        //text_paint.setTextScaleX(3);//水準方向拉伸3倍
        //canvas.drawText("小小的石頭", 100, 300, text_paint);

        //6.canvas繪制文字
        //6.1、drawText
        //drawText(String text, float x, float y, Paint paint)
        //drawText(char[] text, int index, int count, float x, float y, Paint paint)
        //drawText(CharSequence text, int start, int end, float x, float y, Paint paint)
        //下邊兩個方法要求sdk>=23
        //drawTextRun(char[] text, int index, int count, int contextIndex,
        //int contextCount, float x, float y, boolean isRtl, Paint paint)
        //drawTextRun(CharSequence text, int start, int end, int contextStart,
        //int contextEnd, float x, float y, boolean isRtl, Paint paint)
        //第一個構造函數 : 是最普通的。
        //第二個構造函數 : text 位元組數組;index 表示第一個要繪制的文字索引;count 需要繪制的文字個數。
        //第三個構造函數 : text 表示字元 (注意與上面比較);start 開始截取字元的索引号;
        //end 結束截取字元的索引号。(注意和上面的差別) [start , end ) 包含 start 但不包含 end
        //第四個構造函數和第五個構造函數 : contextIndex 和 index 相同 ;
        //contextCount 大于等于 count ; isRtl 表示排列順序,
        //true 表示正序,false 表示倒序(這裡的倒是指第一個字元變到最後一個字元,
        //最後一個字元變到第一個字元)。 注意了drawTextRun方法是在 skd23 才引入的方法。
        //text_paint.setStyle(Paint.Style.FILL);
        //canvas.drawText("我是一顆小小的石頭".toCharArray(), 1, 4, 100, 100, text_paint);
        //canvas.drawText("我是一顆小小的石頭", 1, 4, 100, 200, text_paint);
        //最小sdk23
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //倒序
        //     canvas.drawTextRun("我是一顆小小的石頭".toCharArray(), 1, 4, 1, 4, 100, 400, false, text_paint);
            //正序
        //    canvas.drawTextRun("我是一顆小小的石頭".toCharArray(), 1, 4, 1, 4, 100, 300, true, text_paint);
        // }

        //6.2、drawPosText
        //drawPosText(String text, float[] pos, Paint paint)
        //drawPosText(char[] text, int index, int count, float[] pos, Paint paint)
        //float[] pos = {100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600};
        //canvas.drawPosText("我是一顆小小", pos, text_paint);

        //6.3、drawTextOnPath
        //drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)
        //drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
        //index,count : 和上面截取參數含義一樣,這裡不再累訴。
        //hOffset : 與路徑起點的水準偏移量 ,正數向 X 軸正方向移動(右移);負數向 X 軸負方向移動(左移)
        //如果是圓弧:正數是順時針的偏移量;反之是逆時針的偏移量
        //vOffset : 與路徑中心的垂直偏移量,正數向 Y 軸正方向移動(下移);負數向Y 軸負方向移動(上移)
        //如果是圓弧正數向 Y 軸負方向移動(上移);負數向Y 軸正方向移動(下移)
        //Path mPath = new Path();
        //Paint mpaint = new Paint();
        //mpaint.setStrokeWidth(5);
        //mpaint.setTextSize(80);
        //mpaint.setColor(Color.GREEN);
        //mpaint.setStyle(Paint.Style.STROKE);
        //6.3.1
        //mPath.moveTo(100, 100);
        //mPath.lineTo(800, 100);
        //canvas.drawPath(mPath, mpaint);
        //canvas.drawTextOnPath("我是一顆小小的石頭", mPath,10, 100, text_paint);
        //6.3.2
        //mPath.addCircle(500, 500, 200, Path.Direction.CW);
        //canvas.drawPath(mPath, mpaint);
        //canvas.drawTextOnPath("我是一顆小小的石頭", mPath, 40,20, text_paint);

        //6.4、Typeface(字型樣式設定)
        //setTypeface(Typeface typeface)
        //參數類型是枚舉類型,枚舉值如下:
        //Typeface.NORMAL //正常體
        //Typeface.BOLD //粗體
        //Typeface.ITALIC //斜體
        //Typeface.BOLD_ITALIC //粗斜體
        //Typeface是用來設定字型樣式的,通過paint.setTypeface()來指定。
        //可以指定系統中的字型樣式,也可以指定自定義的樣式檔案中擷取。
        //要建構Typeface時,可以指定所用樣式的正常體、斜體、粗體等,如果指定樣式中,
        //沒有相關文字的樣式就會用系統預設的樣式來顯示,一般預設是宋體。
        //Typeface typeface;
        //typeface = Typeface.create("宋體", Typeface.NORMAL);
        //text_paint.setTypeface(typeface);
        //canvas.drawText("我是一顆小小的石頭", 100, 100, text_paint);
        //設定楷體根本沒起作用,在系統的字型當中沒有找到楷體。
        //typeface = Typeface.create("楷體", Typeface.NORMAL);
        //mPaint.setTypeface(typeface);
        //canvas.drawText("我是一顆小小的石頭", 100, 200, mPaint);
        //----------------------------------------------------------
        //自定義字型
        //createFromAsset(AssetManager mgr, String path) //Asset中擷取
        //createFromFile(File path) //檔案路徑擷取
        //createFromFile(String path) //外部路徑擷取
        //首先在main下建立assets檔案夾,然後在assets檔案夾建立fonts檔案夾,
        //最後在fonts檔案夾下放入font1.ttf
        Typeface typeface;
        typeface = Typeface.createFromAsset(mcontext.getAssets(), "fonts/font1.ttf");
        //Typeface.createFromFile(mContext.getFilesDir()+"/font1.ttf")
        text_paint.setTypeface(typeface);
        canvas.drawText("我是一顆小小的石頭", , , text_paint);

        typeface = Typeface.createFromAsset(mcontext.getAssets(), "fonts/font2.ttf");
        text_paint.setTypeface(typeface);
        canvas.drawText("我是一顆小小的石頭", , , text_paint);
    }
}