目录
一、前言
二、Canvas中的书法家API
三、实战
四、写在最后
一、前言
canvas 的 API 方法相当之多,小盆友本篇文章之前已经分享了 “Canvas中的裁剪师” 和 “Canvas中的绘图师”,今天分享的是文字方面的API。
在分享前,小盆友啰嗦两句,有些童鞋说 canvas 的这几篇文章是初级文章和 “Android高级UI” 这几个字显得有些格格不入。小盆友借此解释下,canvas 的这几篇文章是作为 高级UI 文章的补充,是这系列文章中的 垫脚石,并非想做 “标题党” 来吸引流量(貌似一直也没什么流量😂)。
啰嗦了这么多,来看看今天的实战效果图
抖动的字符
二、Canvas中的书法家API
1、drawText(四个重载方法)
(1)第一个 drawText 函数
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
描述: 在坐标为 (x,y) 处绘制 text 字符串。
举个例子:
private static final String CONTENT = "zinc 猛猛的小盆友";
canvas.drawText(CONTENT, -300, -500, mPaint);
效果图
(2)第二个 drawText 函数
public void drawText(@NonNull String text, int start, int end, float x, float y,
@NonNull Paint paint)
描述: 在坐标为 (x,y) 处绘制字符串text,从下标为start的字符开始,到下标为 (end-1) 的字符终止。
举个例子:
private static final String CONTENT = "zinc 猛猛的小盆友";
// 绘制内容为从CONTENT的第四个字符开始,到CONTENT最后一个字符
canvas.drawText(CONTENT, 3, CONTENT.length(), -300, -400, mPaint);
效果图
(3)第三个 drawText 函数
public void drawText(@NonNull char[] text, int index, int count, float x, float y,
@NonNull Paint paint)
描述: 在坐标为 (x,y) 处绘制 text,从下标为start开始,绘制count个字符。
举个例子
private static final char[] C = "https://github.com/zincPower/UI2018".toCharArray();
canvas.drawText(C, 0, C.length, -300, -100, mPaint);
canvas.drawText(C, 5, 10, -300, 0, mPaint);
效果图
(4)第四个 drawText 函数
public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
@NonNull Paint paint)
描述: 在坐标为 (x,y) 处绘制 text,从下标为start的字符开始,到下标为 (end-1) 的字符终止。
举个例子
private static final CharSequence SEQ = "https://blog.csdn.net/weixin_37625173";
canvas.drawText(SEQ, 0, SEQ.length(), -300, 300, mPaint);
canvas.drawText(SEQ, 6, 20, -300, 400, mPaint);
效果图
2、drawTextOnPath (两个重载方法)
(1)第一个 drawTextOnPath 函数
public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
float vOffset, @NonNull Paint paint)
描述: 在 路径path 上绘制 text。
特殊参数说明:
1)hOffset:水平偏移量
2)vOffset:垂直偏移量
举个例子
private static final String CONTENT = "zinc 猛猛的小盆友";
// mPath 是一个贝塞尔曲线绘制的路径
canvas.drawTextOnPath(CONTENT, mPath, 0, 0, mPaint);
效果图
(2)第二个 drawTextOnPath 函数
public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
float hOffset, float vOffset, @NonNull Paint paint)
描述: 在 路径path 上绘制 text。
特殊参数说明:
1)index:从下标为index的字符开始绘制
2)count:绘制字符的个数
3)hOffset:水平偏移量
4)vOffset:垂直偏移量
例子
private static final char[] C = "https://blog.csdn.net/weixin_37625173".toCharArray();
// 从下标为2的字符(即第三个字符)开始,绘制20个字符
canvas.drawTextOnPath(C, 2, 20, mPath, 0, 0, mPaint);
效果图
3、drawTextRun
这个方法不做过多的解释,因为在实际开发中使用可以说较少。简单概括这个方法的作用,他是为了处理一些语言文字(例如:阿拉伯语),当一个字在一个词语中,会受左右的字影响而进行变形的情况。
这方面的语言小盆友不懂,所以没法举出严谨的例子,请有需要的童鞋移步Demo中自行体会。
public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)
public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)
4、drawPosText(两个重载方法)
(1)第一个 drawPosText 函数
public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
@NonNull Paint paint)
描述: 在pos对应的坐标上绘制text。
举个例子
private static final String CONTENT = "猛猛的小盆友";
private static final float[] pos1 = new float[]{
-300, -600,
-250, -500,
-200, -400,
-150, -300,
-100, -200,
-50, -100,
};
// 每个字符 和 pos的坐标要一一对应的上,否则crash
canvas.drawPosText(CONTENT, pos1, mPaint);
效果图
(2)第二个 drawPosText 函数
public void drawPosText(@NonNull char[] text, int index, int count,
@NonNull @Size(multiple = 2) float[] pos,
@NonNull Paint paint)
描述: 在pos对应的坐标上绘制text,从下标为index的字符开始,绘制count个。
举个例子
private static final String CONTENT = "猛猛的小盆友";
private static final float[] pos2 = new float[]{
-300, 100,
-250, 200,
-200, 300,
-150, 400,
-100, 500,
};
canvas.drawPosText(CONTENT.toCharArray(), 1, 4, pos2, mPaint);
效果图
三、实战
抖动的字符
Github入口:传送门
编码思路
在这一实战中,其实 drawTextOnPath
反倒不是主角,他只是负责在我们的 path 上将文字绘出即可,所以童鞋们知道了最主要的是 path 的确定。
获取 path 上的点,是通过如下的函数获取
private float calculateY(float x) {
double a = Math.pow(4 / (4 + Math.pow(4 * x / mLength, 4)), 2.5f) * mA;
return (float) (a * Math.sin(Math.PI * x / 200 - m));
}
具体的函数图形如下
image
公式的最初原型来源于此博客,在此谢谢博主。
看完这函数,可能有些童鞋比较懵逼,小盆友稍微给一些简单解释(毕竟难的我也说不清😂),我们将此公式抽象一下,便是如下形状:
A*sin(w*x+m)+k
这就是我们在初中学的三角函数:正弦函数sin。我们罗列下几个参数的作用:
- A:管理 正弦函数 的振幅,即上下摆动的幅度;
- w:管理 正弦函数 的水平收缩幅度;
- m:管理 正弦函数 的水平偏移量;
- k:管理 正弦函数 的垂直偏移量;
在我们这里的场景中,主要控制两个参数:
- A 的振幅变动,上面函数图中在靠近 x=0 的地方函数的震动幅度变大,所以我们将 x的值 考虑进 A的计算中,并且以分母的形式(分母越大,数值越小;分母越小,数值越大)
- m 的水平偏移,正弦的一个周期是 2π,所以我们这里的曲直只需要从 [0-2π] 的一个范围即可。
让字符串摇摆起来
经过上面的简单分析,我们需要的各种零件也都准备好了,最后加入我们再熟悉不过的 属性动画,就可以让这条 路径path 动起来。路径path 动起来,会导致绘制在上面文字也动起来。
mAnimator = ValueAnimator.ofFloat(0, (float) (2 * Math.PI));
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float progress = (float) animation.getAnimatedValue();
m = progress;
mA = (float) (1 - progress / (2 * Math.PI)) * A;
invalidate();
}
});
mAnimator.setDuration(1000);
四、写在最后
这次的文章较为简单和基础,只是小盆友有点强迫症,必须要把 canvas 的每个API都过一遍和记录一下。
如果觉得文章对你有所启发,请给我个赞吧,如果发现有那些欠妥的地方,请留言区与我讨论,我们共同进步。
高级UI系列的Github地址:请进入传送门,如果喜欢的话给我一个star吧😄
欢迎加我微信,我们可以进行更多更有趣的交流
image
网友评论