Keywords: Android TextView
github:https://github.com/hanks-zyh/HTextView
本篇blog为博主迁移博客到简书的第一篇,希望各位喜欢。深入github Android系列文章主要是博主梳理github上托管的Android项目,按照关键字搜索、star排序找到项目,进行学习理解,最后形成文分享给各位朋友。
HTextView这个开源库项目结构是非常清晰的,HTextView-Base基类库+scale\fade\line等扩展库,为了更好地了解该库的实现流程导出了一个Line扩展库的UML,效果图如下
HTextView继承TextView并未做什么代码修改,仅仅是作为基类,扩展抽象方法
public abstract class HTextView extends TextView {
//......................略......................
public abstract void setProgress(float progress);
public abstract void animateText(CharSequence text);
}
IHText接口设计,定义init、animateText、onDraw三个函数,init主要用于构造函数读取自定义属性的值,animateText函数根据传入text执行动画,而动画引起重绘,HTextView的重绘代理onDraw,onDraw方法的具体实现稍后再提。
public interface IHText {
void init(HTextView hTextView, AttributeSet attrs, int defStyle);
void animateText(CharSequence text);
void onDraw(Canvas canvas);
}
HText是IHText实现类,针对整个库而已只是一个基类。根据各个扩展库进行扩展。先来了解init方法块
@Override
public void init(HTextView hTextView, AttributeSet attrs, int defStyle) {
mHTextView = hTextView;
mOldText = "";
mText = hTextView.getText();
progress = 1;
mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mOldPaint = new TextPaint(mPaint);
mHTextView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mHTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
mHTextView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
mTextSize = mHTextView.getTextSize();
mWidth = mHTextView.getWidth();
mHeight = mHTextView.getHeight();
oldStartX = mHTextView.getLayout().getLineLeft(0);
initVariables();
}
});
prepareAnimate();
}
抛开基本的变量赋值,就剩下addOnGlobalLayoutListener、initVariables、prepareAnimate三个方法,OnGlobalLayoutListener:当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类,initVariables抽象方法会在子类根据各自扩展库需要进行具体实现(初始化基本变量),prepareAnimate函数主要是为动画准备基础数据,例如初始画笔,记录每个字符的间隙等。
animateText方法即我们调用启动动画,设置进去的文字进行一次记录旧文本和新文本,用于后面文字字符比较记录index,为动画提供基础数据。接着是准备动画的基本数据,最后启动动画
@Override
public void animateText(CharSequence text) {
mHTextView.setText(text);
mOldText = mText;
mText = text;
prepareAnimate();
animatePrepare(text);
animateStart(text);
}
启动动画的具体实现我们找到LineText类里面的animateStart方法一观
@Override
protected void animateStart(CharSequence text) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1)
.setDuration((long) animationDuration);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
progress = (float) animation.getAnimatedValue();
mHTextView.invalidate();
}
});
valueAnimator.start();
}
不难发现,随着进度值的变化不断调用重绘以及进度值全局变量赋值,从而引起ondraw方法的调用,而扩展LineTextView 的onDraw正是用LineText代理实现ondraw函数,关于onDraw函数的实现→drawFrame(),我们进入LineText内部drawFrame方法一观究竟
@Override
protected void drawFrame(Canvas canvas) {
float percent = progress;
float percent2 = (float) (Math.sqrt(3.38f - (percent - 1.7f) * (percent - 1.7f)) - 0.7);
int width = mHTextView.getWidth();
int height = mHTextView.getHeight();
pA.x = 0;
pA.y = 0;
pB.x = width;
pB.y = 0;
pC.x = width;
pC.y = height;
pD.x = 0;
pD.y = height;
p1.x = width * percent2;
p1.y = pB.y;
drawLine(canvas, p1, pB);
p2.x = pB.x;
p2.y = height * percent;
drawLine(canvas, pB, p2);
p3.x = width;
p3.y = height * percent2;
drawLine(canvas, p3, pC);
//............................略............................
p8.x = width * percent;
p8.y = 0;
drawLine(canvas, pA, p8);
}
private void drawLine(Canvas canvas, PointF a, PointF b) {
canvas.drawLine(a.x, a.y, b.x, b.y, mLinePaint);
}
本质也就是绘制了八条线条,只不过线条的长短位置根据progress动态改变,仅此而已!!! 也就有了我们看到的下面的效果图样
网友评论