TextPathView是一个把文字转化为路径动画然后展现出来的自定义控件。效果如上图。
这里有原理解析!
主要的使用流程就是输入文字,然后设置一些动画的属性,还有画笔特效,最后启动就行了。想要自己控制绘画的进度也可以,详情见下面。
compile 'com.yanzhikai:TextPathView:0.1.3'
minSdkVersion 16
如果遇到播放完后消失的问题,请关闭硬件加速,可能是硬件加速对
drawPath()
方法不支持
TextPathView分为两种,一种是每个笔画按顺序刻画的SyncTextPathView,一种是每个笔画同时刻画的AsyncTextPathView,使用方法都是一样,在xml里面配置属性,然后直接在java里面调用startAnimation()方法就行了,具体的可以看例子和demo。下面是一个简单的例子:
xml里面:
<yanzhikai.textpath.SyncTextPathView
android:id="@+id/stpv_2017"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:duration="12000"
app:showPainter="true"
app:text="2017"
app:textInCenter="true"
app:textSize="60sp"
android:layout_weight="1"
/>
<yanzhikai.textpath.AsyncTextPathView
android:id="@+id/atpv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:duration="12000"
app:showPainter="true"
app:text="炎之铠"
app:textStrokeColor="@android:color/holo_orange_light"
app:textInCenter="true"
app:textSize="62sp"
android:layout_gravity="center_horizontal"
/>
java里面使用:
atpv1 = findViewById(R.id.atpv_1);
stpv_2017 = findViewById(R.id.stpv_2017);
//从无到显示
atpv1.startAnimation(0,1);
//从显示到消失
stpv_2017.startAnimation(1,0);
还可以通过控制进度,来控制TextPathView显示,这里用SeekBar:
sb_progress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
atpv1.drawPath(progress / 1000f);
stpv_2017.drawPath(progress / 1000f);
}
}
PathView是0.1.1版本之后新增的,拥有三个子类TextPathView、SyncPathView和AsyncPathView,前者上面有介绍是文字的路径,后面这两个就是图形的路径,必须要输入一个Path类,才能正常运行:
public class TestPath extends Path {
public TestPath(){
init();
}
private void init() {
addCircle(350,300,150,Direction.CCW);
addCircle(350,300,100,Direction.CW);
addCircle(350,300,50,Direction.CCW);
moveTo(350,300);
lineTo(550,500);
}
}
//必须先调用setPath设置路径
aspv.setPath(new TestPath());
aspv.startAnimation(0,1);
(录屏可能有些问题,实际上是没有背景色的)上面就是SyncPathView和AsyncPathView效果,区别和文字路径是一样的。
属性名称 | 意义 | 类型 | 默认值 |
---|---|---|---|
textSize | 文字的大小size | integer | 108 |
text | 文字的具体内容 | String | Test |
autoStart | 是否加载完后自动启动动画 | boolean | false |
showInStart | 是否一开始就把文字全部显示 | boolean | false |
textInCenter | 是否让文字内容处于控件中心 | boolean | false |
duration | 动画的持续时间,单位ms | integer | 10000 |
showPainter | 在动画执行的时候是否执行画笔特效 | boolean | false |
showPainterActually | 在所有时候是否展示画笔特效 | boolean | false |
路径刻画的线条粗细 | dimension | 5px | |
路径刻画的线条颜色 | color | Color.black | |
paintStrokeWidth | 画笔特效刻画的线条粗细 | dimension | 3px |
paintStrokeColor | 画笔特效刻画的线条颜色 | color | Color.black |
repeat | 是否重复播放动画,重复类型 | enum | NONE |
repeat属性值 | 意义 |
---|---|
NONE | 不重复播放 |
RESTART | 动画从头重复播放 |
REVERSE | 动画从尾重复播放 |
PS:showPainterActually属性,由于动画绘画完毕应该将画笔特效消失,所以每次执行完动画都会自动设置为false。因此最好用于使用非自带动画的时候。
//设置画笔特效
public void setPainter(SyncPathPainter painter);
//设置画笔特效
public void setPainter(SyncPathPainter painter);
因为绘画的原理不一样,画笔特效也分两种:
public interface SyncPathPainter extends PathPainter {
//开始动画的时候执行
void onStartAnimation();
/**
* 绘画画笔特效时候执行
* @param x 当前绘画点x坐标
* @param y 当前绘画点y坐标
* @param paintPath 画笔Path对象,在这里画出想要的画笔特效
*/
@Override
void onDrawPaintPath(float x, float y, Path paintPath);
}
public interface AsyncPathPainter extends PathPainter {
/**
* 绘画画笔特效时候执行
* @param x 当前绘画点x坐标
* @param y 当前绘画点y坐标
* @param paintPath 画笔Path对象,在这里画出想要的画笔特效
*/
@Override
void onDrawPaintPath(float x, float y, Path paintPath);
}
看名字就知道是对应哪一个了,想要自定义画笔特效的话就可以实现上面之中的一个或者两个接口来自己画啦。 另外,还有里面已经自带了3种画笔特效,可供参考和使用(关于这些画笔特效的实现,可以参考原理解析):
//箭头画笔特效,根据传入的当前点与上一个点之间的速度方向,来调整箭头方向
public class ArrowPainter implements SyncPathPainter {
//一支笔的画笔特效,就是在绘画点旁边画多一支笔
public class PenPainter implements SyncPathPainter,AsyncPathPainter {
//火花特效,根据箭头引申变化而来,根据当前点与上一个点算出的速度方向来控制火花的方向
public class FireworksPainter implements SyncPathPainter {
由上面可见,因为烟花和箭头画笔特效都需要记录上一个点的位置,所以只适合按顺序绘画的SyncTextPathView,而PenPainter就适合两种TextPathView。仔细看它的代码的话,会发现画起来都是很简单的哦。
自定义画笔特效也是非常简单的,原理就是在当前绘画点上加上一个附加的Path,实现SyncPathPainter和AsyncPathPainter之中的一个或者两个接口,重写里面的onDrawPaintPath(float x, float y, Path paintPath)
方法就行了,如下面这个:
atpv2.setPathPainter(new AsyncPathPainter() {
@Override
public void onDrawPaintPath(float x, float y, Path paintPath) {
paintPath.addCircle(x,y,6, Path.Direction.CCW);
}
});
//设置自定义动画监听
public void setAnimatorListener(PathAnimatorListener animatorListener);
PathAnimatorListener是实现了AnimatorListener接口的类,继承它的时候注意不要删掉super父类方法,因为里面可能有一些操作。
//获取绘画文字的画笔
public Paint getDrawPaint() {
return mDrawPaint;
}
//获取绘画画笔特效的画笔
public Paint getPaint() {
return mPaint;
}
/**
* 开始绘制路径动画
* @param start 路径比例,范围0-1
* @param end 路径比例,范围0-1
*/
public void startAnimation(float start, float end);
/**
* 绘画路径的方法
* @param progress 绘画进度,0-1
*/
public void drawPath(float progress);
/**
* Stop animation
*/
public void stopAnimation();
/**
* Pause animation
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void pauseAnimation();
/**
* Resume animation
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void resumeAnimation();
//直接显示填充好颜色了的全部文字
public void showFillColorText();
由于正在绘画的时候文字路径不是封闭的,填充颜色会变得很混乱,所以这里给出showFillColorText()
来设置直接显示填充好颜色了的全部文字,一般可以在动画结束后文字完全显示后过渡填充,如Demo里面的:
//设置动画播放完后填充颜色
stpv_fortune.setAnimatorListener(new PathAnimatorListener(stpv_fortune){
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
stpv_fortune.showFillColorText();
}
});
stpv_wish.setCanShowPainter(true);
//设置文字内容
public void setText(String text);
//设置路径,必须先设置好路径在startAnimation(),不然会报错!
public void setPath(Path path) ;
//设置字体样式
public void setTypeface(Typeface typeface);
//清除画面
public void clear();
//设置动画时能否显示画笔效果
public void setShowPainter(boolean showPainter);
//设置所有时候是否显示画笔效果,由于动画绘画完毕应该将画笔特效消失,所以每次执行完动画都会自动设置为false
public void setCanShowPainter(boolean canShowPainter);
//设置动画持续时间
public void setDuration(int duration);
//设置重复方式
public void setRepeatStyle(int repeatStyle);
-
2018/03/08 version 0.0.5:
- 增加了
showFillColorText()
方法来设置直接显示填充好颜色了的全部文字。 - 把PathAnimatorListener从TextPathView的内部类里面解放出来,之前使用太麻烦了。
- 增加
showPainterActually
属性,设置所有时候是否显示画笔效果,由于动画绘画完毕应该将画笔特效消失,所以每次执行完动画都会自动将它设置为false。因此它用处就是在不使用自带Animator的时候显示画笔特效。
- 增加了
-
2018/03/08 version 0.0.6:
-
2018/03/18 version 0.1.0:
- 重构代码,加入路径动画SyncPathView和AsyncPathView,把总父类抽象为PathView
- 增加
setDuration()
、setRepeatStyle()
- 修改一系列名字如下:
Old Name | New Name |
---|---|
TextPathPainter | PathPainter |
SyncTextPainter | SyncPathPainter |
AsyncTextPainter | AsyncPathPainter |
TextAnimatorListener | PathAnimatorListener |
- 2018/03/21 version 0.1.2:
- 修复高度warp_content时候内容有可能显示不全
- 原来PathMeasure获取文字Path时候,最后会有大概一个像素的缺失,现在只能在onDraw判断progress是否为1来显示完全路径(但是这样可能会导致硬件加速上显示不出来,需要手动关闭这个View的硬件加速)
- 增加字体设置
- 支持自动换行
- 2018/09/09 version 0.1.3:
- 默认关闭此控件的硬件加速
- 加入内存泄漏控制
- 准备后续优化
- 更多的特效,更多的动画,如果有什么想法和建议的欢迎issue提出来一起探讨,还可以提交PR出一份力。
- 更好的性能,目前单个TextPathView在模拟器上运行动画时是不卡的,多个就有一点点卡顿了,在性能较好的真机多个也是没问题的,这个性能方面目前还没头绪。
- 文字换行符支持。
- Path的宽高测量(包含空白,从坐标(0,0)开始)
如果想为TextPathView的完善出一份力的同学,欢迎提交PR:
- 首先请创建一个分支branch。
- 如果加入新的功能或者效果,请不要覆盖demo里面原来用于演示Activity代码,如FristActivity里面的实例,可以选择新增一个Activity做演示测试,或者不添加演示代码。
- 如果修改某些功能或者代码,请附上合理的依据和想法。
TextPathView遵循MIT协议。
id:炎之铠
炎之铠的邮箱:[email protected]