对于文字逐个打出效果,我们一下子想到的做法可能都是弄一个for循环,不断更改文本内容。
这法子表面看起来可以,但实际实用起来问题多多,比如对于多行居中对齐的文本,打出效果就不是渐进出来,因为受到对齐和换行的影响,随着文字增多,文本布局会不断变化。
下面看最实用和稳定的文字逐个打出效果自定义组件FadeInTextView。
1、FadeInTextView完全继承TextView的所有特性,没有任何负面影响,使用FadeInTextView就像使用TextView一样;
2、简单设置出效果:
(1)setFadeInDuration:设置打出效果总共时长;
(2)setMoveUnitLength:设置渐进步长为几个字符,默认为1;
(3)setFadeInMaskColor:设置遮罩颜色,即未显示文字区域的颜色。
完整源码如下:
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.text.Layout;
import android.util.AttributeSet;
import android.widget.TextView;
public class FadeInTextView extends TextView {
private static final int DEFAULT_UNIT_LENGTH = 2;
private static final int DEFAULT_DURATION = 3820;
private List<Rect> lineRects = new ArrayList<Rect>();
private int duration = DEFAULT_DURATION;
private int moveUnitLength;
private int fromLine = 0;
private int moveCount;
private int fromStart;
private int maskColor;
private Paint paint;
private FadeInListener fadeInListener;
private volatile boolean fadeInFinished = false;
private boolean hasCallListener = false;
public FadeInTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public FadeInTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FadeInTextView(Context context) {
super(context);
}
public boolean isFadeInFinished() {
return fadeInFinished;
}
public void setFadeInDuration(int duration) {
this.duration = duration;
}
public int getFadeInDuration() {
return duration;
}
public void setMoveUnitLength(int moveUnitLength) {
this.moveUnitLength = moveUnitLength;
}
public void setFadeInMaskColor(int maskColor) {
this.maskColor = maskColor;
}
public void setFadeInListener(FadeInListener fadeInListener) {
this.fadeInListener = fadeInListener;
}
public void activateFadeInListener() {
this.hasCallListener = false;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (lineRects.isEmpty()) {
getLineRects();
if (fadeInListener != null && !hasCallListener) {
fadeInListener.onFadeInStart(this);
}
}
if (paint == null) {
paint = new Paint();
paint.setColor(maskColor);
paint.setAntiAlias(true);
paint.setStyle(Style.FILL);
}
for (int i = fromLine; i < lineRects.size(); i++) {
Rect rect = new Rect(lineRects.get(i));
if (i == fromLine) {
rect.left = fromStart;
}
canvas.drawRect(rect, paint);
}
if (!computeNextFrame()) {
fadeInFinished = true;
if (fadeInListener != null && !hasCallListener) {
fadeInListener.onFadeInEnd(this);
hasCallListener = true;
}
return;
}
postDelayed(new Runnable() {
@Override
public void run() {
invalidate();
}
}, duration / moveCount);
}
private boolean computeNextFrame() {
if (lineRects.size() <= fromLine) {
return false;
}
Rect currentLineRect = lineRects.get(fromLine);
if (fromStart >= currentLineRect.right) {
return false;
}
fromStart = fromStart + moveUnitLength;
if (fromStart >= currentLineRect.right) {
fromLine++;
if (lineRects.size() > fromLine) {
fromStart = lineRects.get(fromLine).left;
} else {
fromStart = 0;
}
}
return true;
}
private void getLineRects() {
Layout layout = getLayout();
if (layout == null) {
return;
}
int lineCount = layout.getLineCount();
int totalLength = 0;
for (int i = 0; i < lineCount; i++) {
Rect rect = new Rect();
rect.left = (int) layout.getLineLeft(i);
rect.right = (int) layout.getLineRight(i);
rect.top = layout.getLineTop(i);
rect.bottom = layout.getLineBottom(i);
if (i == 0) {
fromStart = rect.left;
}
lineRects.add(rect);
totalLength = totalLength + rect.width();
}
if (moveUnitLength <= 0) {
moveUnitLength = DEFAULT_UNIT_LENGTH;
}
moveCount = totalLength / moveUnitLength;
if (moveCount <= 0) {
moveCount = 1;
}
}
public static interface FadeInListener {
public void onFadeInStart(TextView tv);
public void onFadeInEnd(TextView tv);
}
}
国际惯例
————————————————————————————————————————————————————————
作者:薄荷记账 (转载请注明原作者)
简洁 稳定 优雅 无限可能!