从宏观上提交了一个自定义View的开创步骤,从细节上更进一步的讲课自定义View的详实绘制方法

上篇小说介绍了自定义View的开创流程,从宏观上付出了一个自定义View的创始步骤,本篇是上一篇小说的接续,介绍了自定义View中四个必备的工具Canvas和Paint,从细节上更进一步的讲授自定义View的详实绘制方法。假若把自定义View比作盖一座房子,那么上篇小说就相当于教会了我们怎么一步步的搭建房子的龙骨,而本篇作品将要教会我们的是为房屋的骨架添砖加瓦直至成型,甚至是怎么装修。

上篇小说介绍了自定义View的开创流程,从宏观上交给了3个自定义View的创始步骤,本篇是上一篇小说的一连,介绍了自定义View中多个需要的工具Canvas和Paint,从细节上更进一步的任课自定义View的详细绘制方法。假使把自定义View比作盖一座房子,那么上篇著作就一定于教会了我们怎么一步步的搭建房子的龙骨,而本篇小说将要教会我们的是为房子的骨架添砖加瓦直至成型,甚至是怎么装修。

Canvas

为了后文更为方便的讲课Canvas的常用方法的利用,大家先来做一些预备干活,创立三个自定义View框架,先开始化一下Paint画笔,并安装相关方法:

public class StudyView extends View {

    private Paint mPaint;
    private Context mContext;

    public StudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setStrokeWidth(5); // 设置笔尖宽度
        mPaint.setStyle(Paint.Style.STROKE); // 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

Canvas

为了后文更为便利的上课Canvas的常用方法的应用,大家先来做一些备选工作,创设一个自定义View框架,先开头化一下Paint画笔,并设置相关办法:

public class StudyView extends View {

    private Paint mPaint;
    private Context mContext;

    public StudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setStrokeWidth(5); // 设置笔尖宽度
        mPaint.setStyle(Paint.Style.STROKE); // 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

制图圆弧和扇形

Canvas提供drawArc()方法,通过传递分歧的参数可用来绘制圆弧和扇形,此措施有三个重载方法,详细参数如下:

  • drawArc(float left, float top, float right, float bottom, float
    startAngle, float sweepAngle, boolean useCenter, Paint paint)
  1. left:扇形或圆弧所占区域的左侧界线x坐标
  2. top:扇形或圆弧所占区域的上方界线y坐标
  3. right:左边界线x坐标
  4. bottom:上边界线y坐标
  5. startAngle:扇形或圆弧的原初角度
  6. sweepAngle:扫过的角度
  7. userCenter:此参数可以理解为true正是画扇形,false就是画圆弧
  8. paint:画笔
  • drawArc(RectF oval, float startAngle, float sweepAngle, boolean
    useCenter, Paint paint)

此措施第②个参数是一个RectF类,也是境界,就是把三个办法的left,top,right,bottom封装到了RectF类中,剩余参数与上3个措施一致。

接下去用着三个重载方法分别绘制多少个90°的扇形和三个90°的拱形:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 绘制扇形
    canvas.drawArc(0, 0, 200, 200, 0, 90, true, mPaint);
    RectF rectF = new RectF(0, 0, 200, 200);
    canvas.drawArc(rectF, 180, 90, true, mPaint);

    // 绘制圆弧
    canvas.drawArc(300, 0, 500, 200, 0, 90, false, mPaint);
    RectF rectF1 = new RectF(300, 0, 500, 200);
    canvas.drawArc(rectF1, 180, 90, false, mPaint);
}

绘制效果如下图所示,别的部需要要验证的一些是,drawArc的第伍个参数startAngle中的角度,0°是指坐标系中第5象限中与x重合的角度,顺时针方向代表角度增大的大势,如下图中棕色线条所示。

图片 1

制图圆弧和扇形

Canvas提供drawArc()方法,通过传递不相同的参数可用来绘制圆弧和扇形,此方法有四个重载方法,详细参数如下:

  • drawArc(float left, float top, float right, float bottom, float
    startAngle, float sweepAngle, boolean useCenter, Paint paint)
  1. left:扇形或圆弧所占区域的左边界线x坐标
  2. top:扇形或圆弧所占区域的顶端界线y坐标
  3. right:左边界线x坐标
  4. bottom:上面界线y坐标
  5. startAngle:扇形或圆弧的序幕角度
  6. sweepAngle:扫过的角度
  7. userCenter:此参数能够驾驭为true就是画扇形,false正是画圆弧
  8. paint:画笔
  • drawArc(RectF oval, float startAngle, float sweepAngle, boolean
    useCenter, Paint paint)

此方法第3个参数是二个RectF类,也是境界,正是把2个办法的left,top,right,bottom封装到了RectF类中,剩余参数与上三个主意一致。

接下去用着多个重载方法分别绘制四个90°的扇形和五个90°的圆弧:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 绘制扇形
    canvas.drawArc(0, 0, 200, 200, 0, 90, true, mPaint);
    RectF rectF = new RectF(0, 0, 200, 200);
    canvas.drawArc(rectF, 180, 90, true, mPaint);

    // 绘制圆弧
    canvas.drawArc(300, 0, 500, 200, 0, 90, false, mPaint);
    RectF rectF1 = new RectF(300, 0, 500, 200);
    canvas.drawArc(rectF1, 180, 90, false, mPaint);
}

绘制效果如下图所示,别的部供给要表明的少数是,drawArc的第⑤个参数startAngle中的角度,0°是指坐标系中第5象限中与x重合的角度,顺时针方向代表角度增大的动向,如下图中深灰线条所示。

图片 2

绘制Bitmap

在Canvas中提供了drawBitmap方法,此办法可以让我们一向得到一张图片绘制到画布上,有了它可以让大家的自定义View猛虎添翼,同时也让大家落到实处部分错综复杂效果有了2个尤其惠及的路径。上边是drawBitmap的多少个比较常用的重载方法:

  • drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
  1. bitmap:Bitmap能源文件
  2. left和top:代表了图片左上角落入的职分坐标。
  3. top:看2
  4. paint:画笔
  • drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
  1. src:在Bitmap图片上截取一有的作为绘制源,可null
  2. det:将绘制指标拉伸平铺到det内定的矩形中
  • drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
    同第二个重载方法,差不多第一毛纺织厂一样。

  • drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

  1. matrix:Matrix的参数字传送入是的drawBitmap作用变得卓殊强硬,让此措施有意思了广大,通过matrix能够兑现图片的运动(postTranslate())、缩放(postScale())、旋转(postRotate())、错切(postSkew())等等花式炫酷效果,由于Matrix的用法稍微多一些,篇幅限制,那里就先一带而过了,感兴趣的爱侣能够活动探索。

在onDraw方法中drawBitmap的上述重载方法,注意在应用完Bitmap之后记得用Bitmap.recycle()来回收掉能源,避防备oom。

/** drawBitmap */
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), android.R.mipmap.sym_def_app_icon);
// 绘制图片
canvas.drawBitmap(bitmap, 0, 300, null);
// 将图片拉伸平铺在RectF矩形内
canvas.drawBitmap(bitmap, null, new RectF(200, 300, 500, 500), null);
// 截取图片的四分之一拉伸平铺在RectF矩形内
canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2), new RectF(500, 300, 800, 500), null);

Matrix matrix = new Matrix();
matrix.postTranslate(800, 300); // 将bitmap平移到此位置
canvas.drawBitmap(bitmap, matrix, mPaint);

// 为防止oom,及时回收bitmap
bitmap.recycle();

效益如下图(红框内)。

图片 3

绘制Bitmap

在Canvas中提供了drawBitmap方法,此办法能够让我们平素得到一张图片绘制到画布上,有了它能够让我们的自定义View猛虎添翼,同时也让大家落实部分繁杂效果有了3个进一步方便人民群众的门道。下面是drawBitmap的多少个比较常用的重载方法:

  • drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
  1. bitmap:Bitmap能源文件
  2. left和top:代表了图片左上角落入的职务坐标。
  3. top:看2
  4. paint:画笔
  • drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
  1. src:在Bitmap图片上截取一有个别作为绘制源,可null
  2. det:将绘制目的拉伸平铺到det钦命的矩形中
  • drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
    同第1个重载方法,差不离一毛一样。

  • drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

  1. matrix:Matrix的参数字传送入是的drawBitmap功能变得不得了强硬,让此措施有意思了重重,通过matrix能够兑现图片的移位(postTranslate())、缩放(postScale())、旋转(postRotate())、错切(postSkew())等等花式炫酷效果,由于Matrix的用法稍微多一些,篇幅限制,那里就先一带而过了,感兴趣的对象能够自行探索。

在onDraw方法中drawBitmap的以上海重机厂载方法,注目的在于运用完Bitmap之后记得用Bitmap.recycle()来回收掉财富,以预防oom。

/** drawBitmap */
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), android.R.mipmap.sym_def_app_icon);
// 绘制图片
canvas.drawBitmap(bitmap, 0, 300, null);
// 将图片拉伸平铺在RectF矩形内
canvas.drawBitmap(bitmap, null, new RectF(200, 300, 500, 500), null);
// 截取图片的四分之一拉伸平铺在RectF矩形内
canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2), new RectF(500, 300, 800, 500), null);

Matrix matrix = new Matrix();
matrix.postTranslate(800, 300); // 将bitmap平移到此位置
canvas.drawBitmap(bitmap, matrix, mPaint);

// 为防止oom,及时回收bitmap
bitmap.recycle();

成效如下图(红框内)。

图片 4

制图圆形

  • drawCircle(float cx, float cy, float radius, Paint paint)
  1. cx:圆心x坐标
  2. cy:圆心y坐标
  3. radius:半径

canvas.drawCircle(100, 700, 100, mPaint);

成效如下图:

图片 5

制图圆形

  • drawCircle(float cx, float cy, float radius, Paint paint)
  1. cx:圆心x坐标
  2. cy:圆心y坐标
  3. radius:半径

canvas.drawCircle(100, 700, 100, mPaint);

功效如下图:

图片 6

绘制点

  • drawPoint(float x, float y, Paint paint)
  1. x:点的x坐标
  2. y:点的y坐标
  • drawPoints(float[] pts, Paint paint) 绘制一组点
  1. pts:float数组,两位为一组,两两重组代表x、y坐标,例如:pts[0]、pts[1]意味着第三个点的x、y坐标,pts[2]、pts[3]意味着第三个点的x、y坐标,依次类推。
  • drawPoints(float[] pts, int offset, int count, Paint paint)
    绘制一组点
  1. pts:float数组,两位为一组,两两组成代表x、y坐标,例如:pts[0]、pts[1]意味着首先个点的x、y坐标,pts[2]、pts[3]代表第四个点的x、y坐标,依次类推。
  2. offset:代表数组初步跳过多少个只早先绘制点,注意那里不是指数组的下标,而是意味着跳过多少个值。
  3. count:在跳过offset个值后,处理多少个值,注意那里的count不是代表点的个数,而是表示数组中值的个数。

canvas.drawPoint(100, 700, mPaint); // 绘制一个点

float[] points = new float[] {
    130, 700,
    160, 700,
    190, 700,
    210, 700,
    240, 700
};

canvas.drawPoints(points, 2, 4, mPaint); // 绘制一组点(代表跳过前两个值,处理4个值,也就是实际绘制2个点)

成效如下图:

图片 7

绘制点

  • drawPoint(float x, float y, Paint paint)
  1. x:点的x坐标
  2. y:点的y坐标
  • drawPoints(float[] pts, Paint paint) 绘制一组点
  1. pts:float数组,两位为一组,两两结缘代表x、y坐标,例如:pts[0]、pts[1]意味着第①个点的x、y坐标,pts[2]、pts[3]意味着第叁个点的x、y坐标,依次类推。
  • drawPoints(float[] pts, int offset, int count, Paint paint)
    绘制一组点
  1. pts:float数组,两位为一组,两两组合代表x、y坐标,例如:pts[0]、pts[1]代表首先个点的x、y坐标,pts[2]、pts[3]代表第二个点的x、y坐标,依次类推。
  2. offset:代表数组开头跳过多少个只开始绘制点,注意那里不是指数组的下标,而是表示跳过多少个值。
  3. count:在跳过offset个值后,处理多少个值,注意那里的count不是代表点的个数,而是意味着数组中值的个数。

canvas.drawPoint(100, 700, mPaint); // 绘制一个点

float[] points = new float[] {
    130, 700,
    160, 700,
    190, 700,
    210, 700,
    240, 700
};

canvas.drawPoints(points, 2, 4, mPaint); // 绘制一组点(代表跳过前两个值,处理4个值,也就是实际绘制2个点)

职能如下图:

图片 8

绘制椭圆

  • drawOval(float left, float top, float right, float bottom, Paint
    paint)
  1. left
  2. top
  3. right
  4. bottom

在left、top、right、bottom围成的区域内绘制3个椭圆。

  • drawOval(RectF oval, Paint paint)
  1. 将率先个重载方法的left、top、right、bottom封装到RectF类中,与扇形的重载方法异曲同工。

RectF rectF2 = new RectF(300, 600, 700, 800); // 创建一个RectF
canvas.drawOval(rectF2, mPaint);

职能如下图:

图片 9

制图椭圆

  • drawOval(float left, float top, float right, float bottom, Paint
    paint)
  1. left
  2. top
  3. right
  4. bottom

在left、top、right、bottom围成的区域内绘制二个椭圆。

  • drawOval(RectF oval, Paint paint)
  1. 将第1个重载方法的left、top、right、bottom封装到RectF类中,与扇形的重载方法异曲同工。

RectF rectF2 = new RectF(300, 600, 700, 800); // 创建一个RectF
canvas.drawOval(rectF2, mPaint);

职能如下图:

图片 10

绘图矩形

  • drawRect(float left, float top, float right, float bottom, Paint
    paint)
  • drawRect(Rect r, Paint paint)
  • drawRect(RectF rect, Paint paint)

drawRect的参数卓殊好通晓,那里就不啰嗦了,直接上代码看效率:

canvas.drawRect(rectF2, mPaint);

注:那里的rectF2即上文绘制椭圆时创立的RectF对象。

图片 11

制图矩形

  • drawRect(float left, float top, float right, float bottom, Paint
    paint)
  • drawRect(Rect r, Paint paint)
  • drawRect(RectF rect, Paint paint)

drawRect的参数卓殊好掌握,这里就不啰嗦了,直接上代码看功效:

canvas.drawRect(rectF2, mPaint);

注:那里的rectF2即上文绘制椭圆时创制的RectF对象。

图片 12

绘制圆角矩形

  • drawRoundRect(float left, float top, float right, float bottom,
    float rx, float ry, Paint paint)
  • drawRoundRect(RectF rect, float rx, float ry, Paint paint)

drawRoundRect是绘制圆角矩形,用法和drawRect类似,唯一不一致的是多了七个参数:

  1. rx:x轴方向的圆角弧度
  2. ry:y轴方向的圆角弧度

上代码,看效果:

canvas.drawRoundRect(rectF2, 60, 30, mPaint);

那里为了优异八个方向的圆角弧度,特地将rx和ry设置差别相比大,效果如下图:

图片 13

绘图圆角矩形

  • drawRoundRect(float left, float top, float right, float bottom,
    float rx, float ry, Paint paint)
  • drawRoundRect(RectF rect, float rx, float ry, Paint paint)

drawRoundRect是绘制圆角矩形,用法和drawRect类似,唯一不相同的是多了八个参数:

  1. rx:x轴方向的圆角弧度
  2. ry:y轴方向的圆角弧度

上代码,看效果:

canvas.drawRoundRect(rectF2, 60, 30, mPaint);

此处为了优异四个样子的圆角弧度,特地将rx和ry设置差异相比较大,效果如下图:

图片 14

绘制直线

  • drawLine(float startX, float startY, float stopX, float stopY, Paint
    paint)
  • drawLines(float[] pts, int offset, int count, Paint paint)
  • drawLines(float[] pts, Paint paint)

drawLine和drawLines2个是绘制2个点,八个是绘制一组点,当中drawLines中的float数组中三个值为一组点,其用法能够参照drawPoints。

canvas.drawLine(100, 820, 800, 820, mPaint);

float[] lines = new float[]{
        100f, 850f, 800f, 850f,
        100f, 900f, 800f, 900f,
        100f, 950f, 800f, 950f
};
canvas.drawLines(lines, mPaint); // 按floats数组中,四个数为1组,绘制多条线

功效如下图:

图片 15

绘制直线

  • drawLine(float startX, float startY, float stopX, float stopY, Paint
    paint)
  • drawLines(float[] pts, int offset, int count, Paint paint)
  • drawLines(float[] pts, Paint paint)

drawLine和drawLines二个是绘制三个点,贰个是绘制一组点,个中drawLines中的float数组中八个值为一组点,其用法能够参照drawPoints。

canvas.drawLine(100, 820, 800, 820, mPaint);

float[] lines = new float[]{
        100f, 850f, 800f, 850f,
        100f, 900f, 800f, 900f,
        100f, 950f, 800f, 950f
};
canvas.drawLines(lines, mPaint); // 按floats数组中,四个数为1组,绘制多条线

功能如下图:

图片 16

drawPath() 绘制不规则图形

上边的这个Canvas方法即使已经很有力了,但是我们只要想要绘制一些有失水准的图形如何做,那时候就要用到有力的drawPath()方法了,通过对帕特h进行安装差异的坐标、添加分化图形,最终传入drawPath方法中得以绘制出复杂的且不规则的模样。以下是drawPath的办法及参数:

  • drawPath(Path path, Paint paint)

那里的重中之重参数正是Path,Path类的措施较多,半数以上用法类似,那里挑多少个说一下:

  • Path类
  1. addArc(RectF oval, float startAngle, float sweepAngle)
    往path里面添加3个半圆
  2. addCircle(float x, float y, float radius, Path.Direction dir)
    添加叁个圆形
  3. addOval(RectF oval, Path.Direction dir) 添加二个椭圆
  4. addRect(RectF rect, Path.Direction dir) 添加二个矩形
  5. lineTo(float x, float y) 连线到坐标(x,y)
  6. moveTo(float x, float y) 将path绘制点运动到坐标(x,y)
  7. close()
    用直线闭合图形,调用此方式后,path会将最后一处点与初始用直线连接起来,path早先点为moveTo()方法的坐标上,如果没有调用moveTo()伊始点将私下认可为(0,0)坐标。

接下去使用drawPath绘制一个楼梯:

// 使用 Path 绘制一个楼梯
Path path = new Path();
path.lineTo(0, 1000);
path.lineTo(100, 1000);
path.lineTo(100, 1100);
path.lineTo(200, 1100);
path.lineTo(200, 1200);
path.lineTo(300, 1200);
path.lineTo(300, 1300);
path.lineTo(400, 1300);
path.lineTo(400, 1400);
path.lineTo(0, 1400);
path.lineTo(0, 1000);
path.close();
canvas.drawPath(path, mPaint);

功能如下图:

图片 17

再用drawPath方法绘制七个Android小机器人:

/ 使用 Path 绘制一个Android机器人
// 绘制两个触角
path.reset();
path.moveTo(625, 1050);
path.lineTo(650, 1120);
path.moveTo(775, 1050);
path.lineTo(750, 1120);

path.addArc(new RectF(600, 1100, 800, 1300), 180, 180); // 绘制头部
path.addCircle(666.66f, 1150, 10, Path.Direction.CW); // 绘制眼睛,CW:顺时针绘制, CCW:逆时针绘制
path.addCircle(733.33f, 1150, 10, Path.Direction.CW);
path.addRect(new RectF(600, 1200, 800, 1300), Path.Direction.CW);  // 身体
canvas.drawPath(path, mPaint);

功用图如下:

图片 18

终极,上文中Canvas示例的全方位代码如下:

public class StudyView extends View {

    private Paint mPaint;
    private Context mContext;

    public StudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setStrokeWidth(5); // 设置笔尖宽度
        mPaint.setStyle(Paint.Style.STROKE); // 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /** 1、drawArc */

        // 绘制扇形
        canvas.drawArc(0, 0, 200, 200, 0, 90, true, mPaint);
        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawArc(rectF, 180, 90, true, mPaint);

        // 绘制圆弧
        canvas.drawArc(300, 0, 500, 200, 0, 90, false, mPaint);
        RectF rectF1 = new RectF(300, 0, 500, 200);
        canvas.drawArc(rectF1, 180, 90, false, mPaint);

        /** 2、drawBitmap */
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), android.R.mipmap.sym_def_app_icon);
        // 绘制图片
        canvas.drawBitmap(bitmap, 0, 300, null);
        // 将图片拉伸平铺在RectF矩形内
        canvas.drawBitmap(bitmap, null, new RectF(200, 300, 500, 500), null);
        // 截取图片的四分之一拉伸平铺在RectF矩形内
        canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2), new RectF(500, 300, 800, 500), null);

        Matrix matrix = new Matrix();
        matrix.postTranslate(800, 300); // 将bitmap平移到此位置
        canvas.drawBitmap(bitmap, matrix, mPaint);

        // 为防止oom,及时回收bitmap
        bitmap.recycle();

        /** 3、drawCircle */
        canvas.drawCircle(100, 700, 100, mPaint);

        /** 4、绘制一个点 */
        canvas.drawPoint(100, 700, mPaint); // 绘制一个点

        float[] points = new float[] {
            130, 700,
            160, 700,
            190, 700,
            210, 700,
            240, 700
        };

        canvas.drawPoints(points, 2, 4, mPaint); // 绘制一组点(代表跳过前两个值,处理4个值,也就是实际绘制2个点)


        RectF rectF2 = new RectF(300, 600, 700, 800); // 创建一个RectF

        /** 5、drawOval 绘制椭圆 */
        canvas.drawOval(rectF2, mPaint);

        /** 6、drawRect 绘制矩形*/
        canvas.drawRect(rectF2, mPaint);
        canvas.drawRoundRect(rectF2, 60, 30, mPaint);

        /** 7、drawLine */
        canvas.drawLine(100, 820, 800, 820, mPaint);

        float[] lines = new float[]{
                100f, 850f, 800f, 850f,
                100f, 900f, 800f, 900f,
                100f, 950f, 800f, 950f
        };
        canvas.drawLines(lines, mPaint); // 按floats数组中,四个数为1组,绘制多条线


        /** 8、drawPath */

        // 使用 Path 绘制一个楼梯
        Path path = new Path();
        path.moveTo(0, 1000);
        path.lineTo(100, 1000);
        path.lineTo(100, 1100);
        path.lineTo(200, 1100);
        path.lineTo(200, 1200);
        path.lineTo(300, 1200);
        path.lineTo(300, 1300);
        path.lineTo(400, 1300);
        path.lineTo(400, 1400);
        path.close();
        canvas.drawPath(path, mPaint);

        // 使用 Path 绘制一个Android机器人

        // 绘制两个触角
        path.reset();
        path.moveTo(625, 1050);
        path.lineTo(650, 1120);
        path.moveTo(775, 1050);
        path.lineTo(750, 1120);

        path.addArc(new RectF(600, 1100, 800, 1300), 180, 180); // 绘制头部
        path.addCircle(666.66f, 1150, 10, Path.Direction.CW); // 绘制眼睛,CW:顺时针绘制, CCW:逆时针绘制
        path.addCircle(733.33f, 1150, 10, Path.Direction.CW);
        path.addRect(new RectF(600, 1200, 800, 1300), Path.Direction.CW);  // 身体
        canvas.drawPath(path, mPaint);
    }
}

总体意义图如下:

图片 19

实际Canvas除了能够绘制图形之外,还是能绘制文字,Canvas的绘图像和文字字的措施有drawText()、drawTextOnPath()、drawTextRun()等办法,在绘制文字是和Paint的重组愈加严峻,所以讲绘制文字的格局放在下文和Paint一起讲只怕功效会更好一些,好了,废话不多说了,接下去大家就起来Paint的篇章。

drawPath() 绘制不规则图形

上边的这几个Canvas方法固然已经很强劲了,不过我们只要想要绘制一些畸形的图形如何是好,那时候就要用到无敌的drawPath()方法了,通过对帕特h举办设置区别的坐标、添加差别图形,最终传入drawPath方法中得以绘制出复杂的且不规则的形象。以下是drawPath的主意及参数:

  • drawPath(Path path, Paint paint)

此间的重中之重参数正是Path,帕特h类的不二法门较多,抢先百分之五十用法类似,那里挑多少个说一下:

  • Path类
  1. addArc(RectF oval, float startAngle, float sweepAngle)
    往path里面添加1个弧形
  2. addCircle(float x, float y, float radius, Path.Direction dir)
    添加2个圆形
  3. addOval(RectF oval, Path.Direction dir) 添加2个椭圆
  4. addRect(RectF rect, Path.Direction dir) 添加1个矩形
  5. lineTo(float x, float y) 连线到坐标(x,y)
  6. moveTo(float x, float y) 将path绘制点运动到坐标(x,y)
  7. close()
    用直线闭合图形,调用此措施后,path会将最后一处点与伊始用直线连接起来,path初步点为moveTo()方法的坐标上,倘使没有调用moveTo()初阶点将暗中同意为(0,0)坐标。

接下去使用drawPath绘制3个梯子:

// 使用 Path 绘制一个楼梯
Path path = new Path();
path.lineTo(0, 1000);
path.lineTo(100, 1000);
path.lineTo(100, 1100);
path.lineTo(200, 1100);
path.lineTo(200, 1200);
path.lineTo(300, 1200);
path.lineTo(300, 1300);
path.lineTo(400, 1300);
path.lineTo(400, 1400);
path.lineTo(0, 1400);
path.lineTo(0, 1000);
path.close();
canvas.drawPath(path, mPaint);

成效如下图:

图片 20

再用drawPath方法绘制多少个Android小机器人:

/ 使用 Path 绘制一个Android机器人
// 绘制两个触角
path.reset();
path.moveTo(625, 1050);
path.lineTo(650, 1120);
path.moveTo(775, 1050);
path.lineTo(750, 1120);

path.addArc(new RectF(600, 1100, 800, 1300), 180, 180); // 绘制头部
path.addCircle(666.66f, 1150, 10, Path.Direction.CW); // 绘制眼睛,CW:顺时针绘制, CCW:逆时针绘制
path.addCircle(733.33f, 1150, 10, Path.Direction.CW);
path.addRect(new RectF(600, 1200, 800, 1300), Path.Direction.CW);  // 身体
canvas.drawPath(path, mPaint);

功效图如下:

图片 21

末了,上文中Canvas示例的整个代码如下:

public class StudyView extends View {

    private Paint mPaint;
    private Context mContext;

    public StudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setStrokeWidth(5); // 设置笔尖宽度
        mPaint.setStyle(Paint.Style.STROKE); // 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /** 1、drawArc */

        // 绘制扇形
        canvas.drawArc(0, 0, 200, 200, 0, 90, true, mPaint);
        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawArc(rectF, 180, 90, true, mPaint);

        // 绘制圆弧
        canvas.drawArc(300, 0, 500, 200, 0, 90, false, mPaint);
        RectF rectF1 = new RectF(300, 0, 500, 200);
        canvas.drawArc(rectF1, 180, 90, false, mPaint);

        /** 2、drawBitmap */
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), android.R.mipmap.sym_def_app_icon);
        // 绘制图片
        canvas.drawBitmap(bitmap, 0, 300, null);
        // 将图片拉伸平铺在RectF矩形内
        canvas.drawBitmap(bitmap, null, new RectF(200, 300, 500, 500), null);
        // 截取图片的四分之一拉伸平铺在RectF矩形内
        canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2), new RectF(500, 300, 800, 500), null);

        Matrix matrix = new Matrix();
        matrix.postTranslate(800, 300); // 将bitmap平移到此位置
        canvas.drawBitmap(bitmap, matrix, mPaint);

        // 为防止oom,及时回收bitmap
        bitmap.recycle();

        /** 3、drawCircle */
        canvas.drawCircle(100, 700, 100, mPaint);

        /** 4、绘制一个点 */
        canvas.drawPoint(100, 700, mPaint); // 绘制一个点

        float[] points = new float[] {
            130, 700,
            160, 700,
            190, 700,
            210, 700,
            240, 700
        };

        canvas.drawPoints(points, 2, 4, mPaint); // 绘制一组点(代表跳过前两个值,处理4个值,也就是实际绘制2个点)


        RectF rectF2 = new RectF(300, 600, 700, 800); // 创建一个RectF

        /** 5、drawOval 绘制椭圆 */
        canvas.drawOval(rectF2, mPaint);

        /** 6、drawRect 绘制矩形*/
        canvas.drawRect(rectF2, mPaint);
        canvas.drawRoundRect(rectF2, 60, 30, mPaint);

        /** 7、drawLine */
        canvas.drawLine(100, 820, 800, 820, mPaint);

        float[] lines = new float[]{
                100f, 850f, 800f, 850f,
                100f, 900f, 800f, 900f,
                100f, 950f, 800f, 950f
        };
        canvas.drawLines(lines, mPaint); // 按floats数组中,四个数为1组,绘制多条线


        /** 8、drawPath */

        // 使用 Path 绘制一个楼梯
        Path path = new Path();
        path.moveTo(0, 1000);
        path.lineTo(100, 1000);
        path.lineTo(100, 1100);
        path.lineTo(200, 1100);
        path.lineTo(200, 1200);
        path.lineTo(300, 1200);
        path.lineTo(300, 1300);
        path.lineTo(400, 1300);
        path.lineTo(400, 1400);
        path.close();
        canvas.drawPath(path, mPaint);

        // 使用 Path 绘制一个Android机器人

        // 绘制两个触角
        path.reset();
        path.moveTo(625, 1050);
        path.lineTo(650, 1120);
        path.moveTo(775, 1050);
        path.lineTo(750, 1120);

        path.addArc(new RectF(600, 1100, 800, 1300), 180, 180); // 绘制头部
        path.addCircle(666.66f, 1150, 10, Path.Direction.CW); // 绘制眼睛,CW:顺时针绘制, CCW:逆时针绘制
        path.addCircle(733.33f, 1150, 10, Path.Direction.CW);
        path.addRect(new RectF(600, 1200, 800, 1300), Path.Direction.CW);  // 身体
        canvas.drawPath(path, mPaint);
    }
}

完全意义图如下:

图片 22

事实上Canvas除了能够绘制图形之外,还是能够绘制文字,Canvas的绘图像和文字字的艺术有drawText()、drawTextOnPath()、drawTextRun()等艺术,在绘制文字是和Paint的构成尤其紧密,所以讲绘制文字的方法放在下文和Paint一起讲大概成效会更好有的,好了,废话不多说了,接下去大家就从头Paint的文章。

Paint

为了越发清晰的讲解Paint的用法,先来新建二个自定义类,暂叫PaintStudyView,接下去创造3个它的光景骨架,在此类中定义了部分变量,变量的含义请见注释:

public class PaintStudyView extends View {

    private Paint mTextPaint;  // 绘制文字的Paint
    private Paint mPointPaint; // 绘制参考点的Paint
    private Context mContext;

    private final static float Y_SPACE = 100; // y轴方向的间距

    public PaintStudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true); // 消除锯齿
        mTextPaint.setStrokeWidth(1); // 设置笔尖宽度
        mTextPaint.setStyle(Paint.Style.FILL); // 填充
        mTextPaint.setTextSize(30);

        mPointPaint = new Paint();
        mPointPaint.setAntiAlias(true);
        mPointPaint.setStrokeWidth(5);
        mPointPaint.setColor(Color.RED); // 将参考点的Paint设置为红色
        mPointPaint.setStyle(Paint.Style.STROKE);// 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

Paint

为了尤其清晰的讲课Paint的用法,先来新建八个自定义类,暂叫PaintStudyView,接下去创制贰个它的大致骨架,在此类中定义了有的变量,变量的意义请见注释:

public class PaintStudyView extends View {

    private Paint mTextPaint;  // 绘制文字的Paint
    private Paint mPointPaint; // 绘制参考点的Paint
    private Context mContext;

    private final static float Y_SPACE = 100; // y轴方向的间距

    public PaintStudyView(Context context) {
        super(context);
        init(context);
    }

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

    private void init(Context context) {
        mContext = context;
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true); // 消除锯齿
        mTextPaint.setStrokeWidth(1); // 设置笔尖宽度
        mTextPaint.setStyle(Paint.Style.FILL); // 填充
        mTextPaint.setTextSize(30);

        mPointPaint = new Paint();
        mPointPaint.setAntiAlias(true);
        mPointPaint.setStrokeWidth(5);
        mPointPaint.setColor(Color.RED); // 将参考点的Paint设置为红色
        mPointPaint.setStyle(Paint.Style.STROKE);// 不填充
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

Canvas的绘图像和文字字的连锁办法:

Canvas的绘图像和文字字的有关方法:

drawText()的重载方法

drawText()
是Canvas的绘图像和文字字中的最长用的情势,它只好依据从左至右的普通方式来绘制文字。

  • drawText(String text, float x, float y, Paint paint)
  1. text:待绘制的文字内容
  2. x:文字绘制地方的x坐标
  3. y:文字绘制地点的y坐标
  4. paint:Paint画笔,能够透过Paint.setTextAlign()来控制文字的方面,有:Paint.阿里gn.LEFT(居左),Paint.Align.索罗德IGHT(居右),Paint.Align.CENTE大切诺基(居中)八个职位。
  • drawText(String text, int start, int end, float x, float y, Paint
    paint)
  1. start:代表从text中的第多少个字符初步截取绘制,包括第start个字符。
  2. end:代表截取到text的第多少个字符,不分包第end个字符。

诸如:小编是3个自定义View的控件,start=1,end=6,截取后为:是二个自定

上面四个重载方法能够参照第3个很不难就能了解:

  • drawText(CharSequence text, int start, int end, float x, float y,
    Paint paint)
  • drawText(char[] text, int index, int count, float x, float y,
    Paint paint)

以下示例表明了文字的不比岗位,同时也作证了第四个和第5个重载方法对字符串截取时的用法:

String str = "我是一个自定义View的控件";// 待绘制文字

float x = getWidth() / 2;
float y = 100;
canvas.drawPoint(x, y, mPointPaint); // 绘制参考点,便于观察文字处于x,y坐标的位置,从而来学习setTextAlign()方法

mTextPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(str, x, y, mTextPaint);

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(str, 0, 6, x, y, mTextPaint);

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(str.toCharArray(), 1, 6, x, y, mTextPaint);

作用图如下:

图片 23

里面包车型地铁红点为额外添加的参阅坐标,目标是为着卓越setTextAlign中参数的地点。

drawText()的重载方法

drawText()
是Canvas的绘图像和文字字中的最长用的格局,它不得不根据从左至右的平凡形式来绘制文字。

  • drawText(String text, float x, float y, Paint paint)
  1. text:待绘制的文字内容
  2. x:文字绘制地方的x坐标
  3. y:文字绘制位置的y坐标
  4. paint:Paint画笔,能够透过Paint.setTextAlign()来支配文字的方向,有:Paint.Align.LEFT(居左),Paint.Align.福睿斯IGHT(居右),Paint.Align.CENTECRUISER(居中)三个职分。
  • drawText(String text, int start, int end, float x, float y, Paint
    paint)
  1. start:代表从text中的第多少个字符开首截取绘制,包蕴第start个字符。
  2. end:代表截取到text的第多少个字符,不含有第end个字符。

比如说:作者是一个自定义View的控件,start=1,end=6,截取后为:是多个自定

上边五个重载方法可以参见第三个很不难就能分晓:

  • drawText(CharSequence text, int start, int end, float x, float y,
    Paint paint)
  • drawText(char[] text, int index, int count, float x, float y,
    Paint paint)

以下示例表达了文字的两样位置,同时也评释了第一个和第五个重载方法对字符串截取时的用法:

String str = "我是一个自定义View的控件";// 待绘制文字

float x = getWidth() / 2;
float y = 100;
canvas.drawPoint(x, y, mPointPaint); // 绘制参考点,便于观察文字处于x,y坐标的位置,从而来学习setTextAlign()方法

mTextPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(str, x, y, mTextPaint);

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(str, 0, 6, x, y, mTextPaint);

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(str.toCharArray(), 1, 6, x, y, mTextPaint);

功效图如下:

图片 24

内部的红点为额外添加的参照坐标,指标是为着卓越setTextAlign中参数的职位。

drawTextOn帕特h()的重载方法

drawTextOnPath()
由艺术名字大家就能够看出来他能够根据帕特h的走平素绘制文字,例如大家在path中盛传一个圆弧,那么绘制出来的文字走向正是圆弧状的,是还是不是很酷,来看一下它的重载方法:

  • drawTextOnPath(String text, Path path, float hOffset, float vOffset,
    Paint paint)
  1. text:同drawText的率先个参数。
  2. path:Path参数,用法在前文已经说过了。
  3. hOffset:水平方向的偏移量。
  4. vOffset:垂直方向的偏移量。

关键点:有好几一定要提的就是,那里的hOffset是周旋于path路径的品位偏移量,而vOffset也是相对于path路径的垂直偏移量,这么说或然还不怎么不明白,结合上面包车型地铁示范来注脚,请仔细回味那里的情趣:

// 1、下开口圆弧方向绘制文字
mTextPaint.setTextAlign(Paint.Align.LEFT);
y += Y_SPACE;
Path path = new Path();
path.addArc(new RectF(x - 150, y, x + 150, y + 300), 180,180);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint); // 按照path路径绘制文字,不偏移
canvas.drawTextOnPath(str, path, 30, 30, mTextPaint);// 向水平、垂直方向各偏移30
canvas.drawTextOnPath(str, path, 60, 60, mTextPaint);// 向水平、垂直方向各偏移60

// 2、上开口圆弧方向绘制文字
path.reset();
y += Y_SPACE;
path.addArc(new RectF(x - 150, y, x + 150, y + 300), 0, 180);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 30, mTextPaint);
canvas.drawTextOnPath(str, path, 60, 60, mTextPaint);
path.close();

// 3、竖直方向绘制文字
path.reset();
path.moveTo(200, y);
path.lineTo(200, y + 4 * Y_SPACE);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 60, mTextPaint);


y += Y_SPACE;
y += Y_SPACE;
y += Y_SPACE;
y += Y_SPACE;

// 4、水平方向绘制文字
path.reset();
path.moveTo(x, y);
path.lineTo(x + 4 * Y_SPACE, y);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 60, mTextPaint);

正如是功效图,注意看图片中的藏蓝部分,普鲁士蓝的线是用代码绘制出来的path参考线,威尼斯红的箭头是path的品位和垂直方向的走向,结合下图能够更好的敞亮drawTextOnPath的hOffset和vOffset参数。

图片 25

  • drawTextOnPath(char[] text, int index, int count, Path path, float
    hOffset, float vOffset, Paint paint)

这些主意的老路想必不用解释了。

drawTextOnPath()的重载方法

drawTextOnPath()
由艺术名字大家就能够看出来他得以根据Path的走平素绘制文字,例如我们在path中传出2个弧形,那么绘制出来的文字走向正是圆弧状的,是或不是很酷,来看一下它的重载方法:

  • drawTextOnPath(String text, Path path, float hOffset, float vOffset,
    Paint paint)
  1. text:同drawText的率先个参数。
  2. path:帕特h参数,用法在前文已经说过了。
  3. hOffset:水平方向的偏移量。
  4. vOffset:垂直方向的偏移量。

关键点:有好几必然要提的正是,那里的hOffset是争论于path路径的档次偏移量,而vOffset也是对峙于path路径的垂直偏移量,这么说可能还多少不领会,结合上面的演示来表达,请仔细回味那里的意味:

// 1、下开口圆弧方向绘制文字
mTextPaint.setTextAlign(Paint.Align.LEFT);
y += Y_SPACE;
Path path = new Path();
path.addArc(new RectF(x - 150, y, x + 150, y + 300), 180,180);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint); // 按照path路径绘制文字,不偏移
canvas.drawTextOnPath(str, path, 30, 30, mTextPaint);// 向水平、垂直方向各偏移30
canvas.drawTextOnPath(str, path, 60, 60, mTextPaint);// 向水平、垂直方向各偏移60

// 2、上开口圆弧方向绘制文字
path.reset();
y += Y_SPACE;
path.addArc(new RectF(x - 150, y, x + 150, y + 300), 0, 180);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 30, mTextPaint);
canvas.drawTextOnPath(str, path, 60, 60, mTextPaint);
path.close();

// 3、竖直方向绘制文字
path.reset();
path.moveTo(200, y);
path.lineTo(200, y + 4 * Y_SPACE);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 60, mTextPaint);


y += Y_SPACE;
y += Y_SPACE;
y += Y_SPACE;
y += Y_SPACE;

// 4、水平方向绘制文字
path.reset();
path.moveTo(x, y);
path.lineTo(x + 4 * Y_SPACE, y);
canvas.drawPath(path, mPointPaint); // 参考弧度线
canvas.drawTextOnPath(str, path, 0, 0, mTextPaint);
canvas.drawTextOnPath(str, path, 30, 60, mTextPaint);

正如是法力图,注意看图片中的豉豆红部分,土黑的线是用代码绘制出来的path参考线,中黄的箭头是path的档次和垂直方向的走向,结合下图能够更好的通晓drawTextOnPath的hOffset和vOffset参数。

图片 26

  • drawTextOnPath(char[] text, int index, int count, Path path, float
    hOffset, float vOffset, Paint paint)

本条点子的老路想必不用解释了。

drawTextRun()的重载方法

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

drawTextRun()能够文字的是从左到右依旧从右到左的相继来绘制,在那之中尾数第②个参数is本田CR-Vtl正是用来支配方向的,true正是倒序绘制,false正是正序绘制,别的的参数就没啥好说的了,这几个艺术用法相比较不难,那里就不贴代码了。别的那一个方法是在API
23才初始添加的,使用时要留意。

到近来停止,Canvas的常用用法基本介绍完了,接下去就足以重点来看Paint的使用了,Paint和Canvas两者是不可分离的,两者同盟,相得益彰。所以在底下的用法示例中难免要用到Canvas的相关措施。

drawTextRun()的重载方法

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

drawTextRun()能够文字的是从左到右依然从右到左的相继来绘制,当中尾数第3个参数is昂Coratl正是用来支配方向的,true正是倒序绘制,false正是正序绘制,其余的参数就没啥好说的了,那几个艺术用法相比简单,那里就不贴代码了。别的那个方式是在API
23才起来添加的,使用时要专注。

到最近停止,Canvas的常用用法基本介绍完了,接下去就能够首要来看Paint的选择了,Paint和Canvas两者是不足分离的,两者合作,相得益彰。所以在上边包车型大巴用法示例中难免要用到Canvas的连带办法。

运用Paint衡量文字的尺码,定位文字

大家在付出自定义控件时,免不了要精分明位文字的文字,例如必须把文字放在某些区域的正中间,只怕必须让一行文字的几何大旨精确的介乎某些点上,那时大家只要不懂那里的良方可能就要盲目标试地点了,那样一点一点试出来的职责很不可信赖,大概换个显示器尺寸地方就窘迫了,接下去怎么来探望哪些用最优雅的姿态来规范的定势文字。

骨子里在档次方向的原则性还比较好说,间接使用Paint.setTextAlign()就能消除大多需求,首即使在档次方向上稍稍复杂一点,想要定位地方,首先供给先得到文字的可观,要用到Paint的以下多个措施:

  • float
    ascent():依照文字大小获取文字顶端到文字基线的偏离(再次来到的是负值)
  • float
    descent():依照文字大小获取文字尾部到文字基线的偏离(再次回到的事正值)

有了那七个方式那就非凡好办了,首先用代码结合职能图说飞鹤下基线、ascent、descent和文字的涉及:

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
canvas.drawLine(x - 300, y, x+300, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.CENTER);// 水平方向上让文字居中
float ascent = mTextPaint.ascent(); // 根据文字大小获取文字顶端到文字基线的距离(返回的是负值)
float descent = mTextPaint.descent(); // 根据文字大小获取文字底部到文字基线的距离(返回的事正值)
canvas.drawLine(x - 300, y + ascent, x+300, y + ascent, mPointPaint);
canvas.drawLine(x - 300, y + descent, x+300, y + descent, mPointPaint);
canvas.drawText(str, x, y, mTextPaint);

效果图如下,它们中间的涉及注意看图片里面包车型大巴辨证。(注:在此地谢谢园友在截图中提出的一处错误,现已纠正)

图片 27

接下去就让文字的主导落在参考试场点上:

// 将文字的中心定位在参考点上
y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
canvas.drawText(str, x, y - ascent / 2 - descent / 2, mTextPaint);

职能图如下,仔细看参考试场点(红点)和文字的职位:

图片 28

动用Paint度量文字的尺寸,定位文字

大家在支付自定义控件时,免不了要精鲜明位文字的文字,例如必须把文字放在某些区域的正中间,只怕必须让一行文字的几何中央规范的介乎某些点上,那时我们若是不懂那里的门路可能就要盲目标试地方了,这样一点一点试出来的岗位很不可信赖赖,大概换个荧屏尺寸地方就窘迫了,接下去怎么来看看哪些用最优雅的姿势来规范的固定文字。

实则在档次方向的固化还比较好说,直接运用Paint.setTextAlign()就能化解大多急需,首要是在档次方向上稍稍复杂一点,想要定位地方,首先要求先得到文字的万丈,要用到Paint的以下八个点子:

  • float
    ascent():依照文字大小获取文字顶端到文字基线的离开(再次来到的是负值)
  • float
    descent():依照文字大小获取文字底部到文字基线的离开(重临的事正值)

有了那些章程那就十分好办了,首先用代码结合职能图说Bellamy(Bellamy)下基线、ascent、descent和文字的涉嫌:

y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
canvas.drawLine(x - 300, y, x+300, y, mPointPaint);
mTextPaint.setTextAlign(Paint.Align.CENTER);// 水平方向上让文字居中
float ascent = mTextPaint.ascent(); // 根据文字大小获取文字顶端到文字基线的距离(返回的是负值)
float descent = mTextPaint.descent(); // 根据文字大小获取文字底部到文字基线的距离(返回的事正值)
canvas.drawLine(x - 300, y + ascent, x+300, y + ascent, mPointPaint);
canvas.drawLine(x - 300, y + descent, x+300, y + descent, mPointPaint);
canvas.drawText(str, x, y, mTextPaint);

效果图如下,它们之间的涉嫌注意看图片里面包车型客车注明。(注:在此间多谢园友在截图中建议的一处错误,现已纠正)

图片 29

接下去就让文字的着力落在参考试场点上:

// 将文字的中心定位在参考点上
y += Y_SPACE;
canvas.drawPoint(x, y, mPointPaint);
canvas.drawText(str, x, y - ascent / 2 - descent / 2, mTextPaint);

功效图如下,仔细看参考试场点(红点)和文字的职分:

图片 30

应用Paint.setShader()(着色器)绘制渐变色

行使 setShader()
方法能够添加渐变颜色也足以动用图片作为背景,其参数是二个Shader类,传入分歧的Shader子类能够兑现不一样的渐变效果还是加上背景图片,其子类有刹那间三种:

  • LinearGradient:线性渐变
  • RadialGradient:放射状渐变
  • SweepGradient:扫描渐变
  • BitmapShader:添加背景图片
  • ComposeShader:多种Shader组合

上面接个Shader的子类在运用格局上都差不离,那里只用LinearGradient为例说澳优下,并注意对LinearGradient构造器的终极3个参数传入分歧的参数对应的功力图:

/* Shader 渐变 */
y = 100;
Shader shader = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.CLAMP);
mTextPaint.setShader(shader);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

y += 3 * Y_SPACE;
Shader shader1 = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.REPEAT);
mTextPaint.setShader(shader1);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

y += 3 * Y_SPACE;
Shader shader2 = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.MIRROR);
mTextPaint.setShader(shader2);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

功能图如下:

图片 31

除了这几个之外上述这个,Paint的用法还有好多广大,权且半会也列不完,博主在那也不得不一得之见,感兴趣的心上人可查看官方API自行探索。


末段想说的是,本连串作品为博主对Android知识实行重复梳理,查缺补漏的学习进度,一方面是对自个儿忘记的事物加以复习重新明白,另一方面相信在重新学习的经过中定会有巨大的新获得,尽管你也有跟自个儿一样的想法,不妨关怀小编一只学学,相互研商,共同进步!

参考文献:

使用Paint.setShader()(着色器)绘制渐变色

运用 setShader()
方法可以添加渐变颜色也得以行使图片作为背景,其参数是二个Shader类,传入不一样的Shader子类能够完结分化的渐变效果依然添加背景图片,其子类有弹指间两种:

  • LinearGradient:线性渐变
  • RadialGradient:放射状渐变
  • SweepGradient:扫描渐变
  • BitmapShader:添加背景图片
  • ComposeShader:多种Shader组合

下面接个Shader的子类在选拔方法上都差不离,那里只用LinearGradient为例说澳优(Beingmate)下,并留意对LinearGradient构造器的最终三个参数字传送入分化的参数对应的成效图:

/* Shader 渐变 */
y = 100;
Shader shader = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.CLAMP);
mTextPaint.setShader(shader);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

y += 3 * Y_SPACE;
Shader shader1 = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.REPEAT);
mTextPaint.setShader(shader1);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

y += 3 * Y_SPACE;
Shader shader2 = new LinearGradient(x - 50, y - 80, x + 50, y + 80,
        Color.parseColor("#FFCCBB"), Color.parseColor("#FF0000"), Shader.TileMode.MIRROR);
mTextPaint.setShader(shader2);
canvas.drawRect(x - 500, y - 80, x + 500, y + 80, mTextPaint);

效益图如下:

图片 32

除去上述这一个,Paint的用法还有为数不少浩大,最近半会也列不完,博主在那也只可以进行试探,感兴趣的对象可查看官方API自行探索。


最后想说的是,本连串小说为博主对Android知识举办再次梳理,查缺补漏的读书进程,一方面是对友好忘记的事物加以复习重新精通,另一方面相信在重新学习的历程中定会有伟大的新收获,要是你也有跟自身同样的想法,不妨关心本人一起学习,互相钻探,共同进步!

参考文献:

相关文章