一,自定义 View 根底:
1,画笔 Paint
文本相干:
办法 | 形容 |
---|---|
setColor(@ColorInt int color) | 设置画笔色彩 |
setStrokeWidth(float width) | 设置画笔粗细 |
setTextSkewX(float f) | 设置歪斜,负右斜,正为左 |
setARGB(int a, int r, int g, int b) | 设置色彩,a为透明度 |
setTextSize(float textSize) | 设置绘制文字大小 |
setFakeBoldText(boolean fakeBoldText) | 是否粗体 |
setTextAlign(Paint.Align align) | 设置文字对齐形式,LEFT,CENTER,RIGHT |
setUnderlineText(boolean underlineText) | 设置下划线 |
setStyle(Style style) | 设置画笔款式,FILL,STROKE,FILL_AND_STROKE setTypeface(Typeface typeface |
位图相干
办法 | 形容 |
---|---|
setDither(boolean dither) | 设置抖动解决 |
setAlpha(int a) | 设置透明度 |
setAntiAlias(boolean aa) | 是否开启抗锯齿 |
setFilterBitmap() | 是否开启优化Bitmap |
setColorFilter(ColorFilter filter) | 设置色彩过滤 |
setMaskFilter(MaskFilter maskfilter) | 设置滤镜的成果 |
setShader(Shader shader) | 设置图像突变成果 |
setStrokeJoin(Paint.Join join) | 设置图像联合形式 |
setXfermode(Xfermode xfermode) | 设置图像重叠成果 |
setPathEffect(PathEffect effect) | 设置门路成果 reset() 复原默认设置 |
2,门路
moveTo() 绘制起始的点lineTo() 绘制连贯的点close() 造成闭环
arcTo() 弧线门路
参数:生成椭圆的矩形、弧线开始的角度、弧线扫描过的角度、是否强制地将弧线的起始点作为绘制起始地位
Region 区域:一块任意形态的关闭图形。应用RegionIterator,用于区域相交填充操作。
3,画布 Canvas
1)革除画布
/** * 画布清屏 */canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
2)绘制画布背景
/** * 绘制画布背景 *///绘制画布背景,argbcanvas.drawARGB(99, 255, 0, 255);canvas.drawRGB(255, 0, 255);canvas.drawColor(Color.LTGRAY);
3)绘制圆形
/** * 绘制圆形 *///设置画笔的根本属性//设置画笔色彩mPaint.setColor(Color.RED);//设置画笔填充款式//仅填充外部mPaint.setStyle(Paint.Style.FILL);//填充外部和描边mPaint.setStyle(Paint.Style.FILL_AND_STROKE);//仅填充描边mPaint.setStyle(Paint.Style.STROKE);//设置描边宽度,单位px,当填充款式是FILL_AND_STROKE时候无效mPaint.setStrokeWidth(20);//应用画布画圆canvas.drawCircle(200, 200, 150, mPaint);mPaint.setColor(Color.BLUE);canvas.drawCircle(200, 200, 130, mPaint);
4)绘制点
/** * 绘制点 *///点的大小mPaint.setStrokeWidth(20);//绘制点,x坐标、y坐标canvas.drawPoint(340, 340, mPaint);
5)绘制直线
/** * 绘制直线 *///直线粗细mPaint.setStrokeWidth(20);//绘制直线终点x坐标、终点y坐标、起点x坐标、起点y坐标canvas.drawLine(360, 360, 660, 660, mPaint);
6)绘制
/** * 绘制矩形 *///矩形的边框粗细mPaint.setStrokeWidth(5);//仅填充矩形描边mPaint.setStyle(Paint.Style.STROKE);//绘制矩形,RectF是保留float类型的矩形,Rect是保留int类型的矩形,左上右下mRectF.set(400F, 400F, 450F, 450F);mRect.set(500, 500, 550, 550);canvas.drawRect(mRectF, mPaint);canvas.drawRect(mRect, mPaint);
7)绘制文字
/** * 绘制文字 * setColor(@ColorInt int color) 设置画笔色彩 * setStrokeWidth(float width) 设置画笔粗细 * setTextSkewX(float f) 设置歪斜,负右斜,正为左 * setARGB(int a, int r, int g, int b) 设置色彩,a为透明度 * setTextSize(float textSize) 设置绘制文字大小 * setFakeBoldText(boolean fakeBoldText) 是否粗体 * setTextAlign(Paint.Align align) 设置文字对齐形式,LEFT,CENTER,RIGHT setUnderlineText(boolean underlineText) 设置下划线 * setStyle(Style style) 设置画笔款式,FILL,STROKE,FILL_AND_STROKE setTypeface(Typeface typeface) 设置Typeface对象,即字体格调,包含粗体,斜体以及衬线体,非衬线体等 */mPaint.setTextSize(90f);canvas.drawText("Android Stack", 200, 1000, mPaint);
二,绘制文字
筹备根底类BaseView,继承View类。
public class BaseView extends View { static final int LINE_OFFSET = 60; protected Paint notePaint = new Paint(); protected Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); protected Rect textRect = new Rect(); public BaseView(Context context) { this(context, null); } public BaseView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BaseView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }}
在 BaseView 里筹备了 2 个画笔。
绘制文字的办法canvas.drawText
,须要指定字符串,绘制起始坐标,画笔 paint。
canvas.drawText(text, x, y, textPaint);
起始坐标的 y 值所在横线在前面也称为 baseline 。
获取文字边界
从图中能够看到文字的局部笔画是能够超出边线的。比方结尾的j
。
应用 Paint.getTextBounds
办法获取文字的边界。
textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // 获取text边界
绘制上图的局部代码
private void drawBounds(Canvas canvas, float tx, float ty, String onShowText) { canvas.drawText(onShowText, tx, ty, textPaint); // 写字 textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // 获取text边界 notePaint.setStrokeWidth(3); notePaint.setColor(Color.parseColor("#EF6C00")); // 右边线 canvas.drawLine(tx, ty - textRect.height() - LINE_OFFSET, tx, ty + LINE_OFFSET, notePaint); // 左边线 canvas.drawLine(tx + textRect.width(), ty - textRect.height() - LINE_OFFSET, tx + textRect.width(), ty + LINE_OFFSET, notePaint); notePaint.setColor(Color.parseColor("#FF0277BD")); // 上边线 canvas.drawLine(tx - LINE_OFFSET, ty - textRect.height(), tx + textRect.width() + LINE_OFFSET, ty - textRect.height(), notePaint); notePaint.setColor(Color.parseColor("#00695C")); // y - baseline canvas.drawLine(tx - LINE_OFFSET, ty, tx + textRect.width() + LINE_OFFSET, ty, notePaint);}
获取 text 尺寸信息
须要应用 Paint.FontMetrics
类。它有 5 个属性
属性 | 介绍 |
---|---|
top | 从baseline到最高的文字顶部的最大间隔 |
ascent | 单行距(singled spaced)时,baseline上方空间的举荐间隔 |
descent | 单行距时,baseline下方空间的举荐间隔 |
bottom | baseline到最下方字符的最大间隔 |
leading | 多行文字之间举荐应用的额定空间 |
应用 Paint.getFontMetrics()
办法获取 Paint.FontMetrics
。
Paint.FontMetrics fm = textPaint.getFontMetrics();
留神,top
和 ascent
是负值。
绘制上图的办法
private void drawFontMetrics(Canvas canvas, float x, float y, String text) { canvas.drawText(text, x, y, textPaint); textPaint.getTextBounds(text, 0, text.length(), textRect); Paint.FontMetrics fm = textPaint.getFontMetrics(); notePaint.setStrokeWidth(1); notePaint.setColor(Color.BLACK); canvas.drawText(String.format(Locale.CHINA, "top:%.2f, bottom:%.2f", fm.top, fm.bottom), x, y + notePaint.getTextSize() * 2.5f, notePaint); canvas.drawText(String.format(Locale.CHINA, "ascent:%.2f, descent:%.2f, leading:%.2f", fm.ascent, fm.descent, fm.leading), x, y + notePaint.getTextSize() * 4f, notePaint); notePaint.setColor(Color.parseColor("#FFD84315")); // fm top线 canvas.drawLine(x - L_BIAS, y + fm.top, x + textRect.width() + L_BIAS, y + fm.top, notePaint); notePaint.setColor(Color.parseColor("#FF00695C")); // fm bottom线 canvas.drawLine(x - L_BIAS, y + fm.bottom, x + textRect.width() + L_BIAS, y + fm.bottom, notePaint); notePaint.setColor(Color.parseColor("#4527A0")); // fm ascent线 canvas.drawLine(x - L_BIAS, y + fm.ascent, x + textRect.width() + L_BIAS, y + fm.ascent, notePaint); notePaint.setColor(Color.parseColor("#0E0822")); // fm descent线 canvas.drawLine(x - L_BIAS, y + fm.descent, x + textRect.width() + L_BIAS, y + fm.descent, notePaint);}
对齐文字两头
有了下面的根底,咱们能够很快晓得如何实现文字“居中对齐”。将文字的程度中心线或竖直中心线对齐到某个点。
例如绘制一个立体坐标系
绘制出2个坐标轴,而后绘制上刻度,并写上数值。 数值文字对应到刻度相应的地位上。咱们次要应用 Paint.getTextBounds
获取到文字的尺寸信息,再计算出适合的地位。
private void drawChart(Canvas canvas) { final float x0 = 100; final float y0 = 300; // 原点在画布上的坐标 final float halfLine = 5; // 刻度长度的一半 textPaint.setColor(Color.BLACK); textPaint.setTextSize(20); notePaint.setStrokeWidth(2); canvas.drawLine(x0, y0, x0 + 500, y0, notePaint); // 绘制横轴 canvas.drawLine(x0, y0, x0, y0 - 290, notePaint); // 绘制纵轴 // 绘制横轴刻度和数字 for (int i = 1; i <= 4; i++) { int step = i * 100; String n = String.valueOf(step); float x = x0 + step; canvas.drawLine(x, y0 - halfLine, x, y0 + halfLine, notePaint); // 刻度 // 文字对齐 textPaint.getTextBounds(n, 0, n.length(), textRect); canvas.drawText(n, x - textRect.width() / 2f, y0 + textRect.height() + halfLine, textPaint); } // 绘制纵轴刻度和数字 for (int i = 1; i <= 2; i++) { int step = i * 100; String n = String.valueOf(step); float y = y0 - step; canvas.drawLine(x0 - halfLine, y, x0 + halfLine, y, notePaint); // 刻度 // 文字对齐 textPaint.getTextBounds(n, 0, n.length(), textRect); canvas.drawText(n, x0 - halfLine * 2 - textRect.width(), y + textRect.height() / 2f, textPaint); } // 绘制原点 0 String origin = "0"; textPaint.getTextBounds(origin, 0, origin.length(), textRect); canvas.drawText(origin, x0 - textRect.width(), y0 + textRect.height(), textPaint);}
三,裁剪画布 canvas clip path
应用 canvas.clipPath(path)
办法。
clipPath
办法相当于按给定的门路裁剪画布。 依据这个用处,咱们能够做出圆角图片的成果。
圆角图片示例
圆角图片是一种常见的设计。Android 官网库中并没有间接显示圆角图片的办法。 如果是纯色,渐变色的背景,咱们能够用 shape 的 corners 来实现圆角。 这里是利用 clipPath
在super.onDraw(canvas)
之前将画布裁出圆角。须要传入一个 Path 来指定裁剪范畴。
新建一个 RoundImageView
类,继承自 AppCompatImageView
。
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Path;import android.util.AttributeSet;import androidx.appcompat.widget.AppCompatImageView;public class RoundImageView extends AppCompatImageView { private float vw, vh; private Path path = new Path(); private float topLeftR; private float topRightR; private float botLeftR; private float botRightR; public RoundImageView(Context context) { this(context, null); } public RoundImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView); topLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topLeftR, 0); topRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topRightR, 0); botLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botLeftR, 0); botRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botRightR, 0); typedArray.recycle(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); vw = getWidth(); vh = getHeight(); } @Override protected void onDraw(Canvas canvas) { path.reset(); if (vw > topLeftR && vh > topRightR) { path.moveTo(topLeftR, 0); path.lineTo(vw - topRightR, 0); path.quadTo(vw, 0, vw, topRightR); path.lineTo(vw, vh - botRightR); path.quadTo(vw, vh, vw - botRightR, vh); path.lineTo(botLeftR, vh); path.quadTo(0, vh, 0, vh - botLeftR); path.lineTo(0, topLeftR); path.quadTo(0, 0, topLeftR, 0); path.close(); canvas.clipPath(path); } super.onDraw(canvas); }}
外面应用了 TypedArray
,须要新增 declare-styleable
资源。
<resources> <declare-styleable name="RoundImageView"> <attr name="topLeftR" format="dimension" /> <attr name="topRightR" format="dimension" /> <attr name="botLeftR" format="dimension" /> <attr name="botRightR" format="dimension" /> </declare-styleable></resources>
应用这个类。在 layout 中间接应用。别离定义 4 个圆角半径参数。给 src
设置纯色。 如果给定图片,图片内容接触到 view 端点时,才会看得出有圆角成果。
<com.rustfisher.tutorial2020.customview.view.RoundImageView style="@style/RoundIvCube" app:botLeftR="8dp" app:botRightR="8dp" app:topLeftR="8dp" app:topRightR="8dp" /><com.rustfisher.tutorial2020.customview.view.RoundImageView style="@style/RoundIvCube" app:botLeftR="25dp" app:botRightR="25dp" app:topLeftR="25dp" app:topRightR="25dp" /><com.rustfisher.tutorial2020.customview.view.RoundImageView style="@style/RoundIvCube" app:botLeftR="16dp" /><com.rustfisher.tutorial2020.customview.view.RoundImageView style="@style/RoundIvCube" app:topLeftR="16dp" /><com.rustfisher.tutorial2020.customview.view.RoundImageView style="@style/RoundIvCube" app:botRightR="16dp" app:topLeftR="16dp" />
style定义
<style name="RoundIvCube"> <item name="android:layout_width">50dp</item> <item name="android:layout_height">50dp</item> <item name="android:src">#303F9F</item> <item name="android:layout_margin">8dp</item> </style>
运行后果
能够看到各个图形的圆角。然而咱们也能发现有锯齿。这个裁剪办法没能做到润滑圆润的圆角。
Android零根底入门教程视频参考