大概搜了一下关于文本跳跃的文章,思想大抵都是来自https://github.com/frakbot/JumpingBeans这儿
大概读了一下源码,没看太懂,大致思想应该是将需要做跳跃的字符串拆成单个文本,然后对单个文本做动画。
动画用到了它自己定义的差值器
/**
* A tweaked {@link android.view.animation.AccelerateDecelerateInterpolator}
* that covers the full range in a fraction of its input range, and holds on
* the final value on the rest of the input range. By default, this fraction
* is 65% of the full range.
*
* @see JumpingBeans.Builder#DEFAULT_ANIMATION_DUTY_CYCLE
*/
private static class JumpInterpolator implements TimeInterpolator {
private final float animRange;
public JumpInterpolator(float animatedRange) {
animRange = Math.abs(animatedRange);
}
@Override
public float getInterpolation(float input) {
// We want to map the [0, PI] sine range onto [0, animRange]
if (input > animRange) {
return 0f;
}
double radians = (input / animRange) * Math.PI;
return (float) Math.sin(radians);
}
}
然后每个文本启动动画的时间延迟不一样
private void initIfNecessary(float ascent) {
if (jumpAnimator != null) {
return;
}
this.shift = 0;
int maxShift = (int) ascent / 2;
jumpAnimator = ValueAnimator.ofInt(0, maxShift);
jumpAnimator
.setDuration(loopDuration)
.setStartDelay(delay);
jumpAnimator.setInterpolator(new JumpInterpolator(animatedRange));
jumpAnimator.setRepeatCount(ValueAnimator.INFINITE);
jumpAnimator.setRepeatMode(ValueAnimator.RESTART);
jumpAnimator.addUpdateListener(this);
jumpAnimator.start();
}
这个setStartDelay(delay)中的delay是由单个文本在字符串中的位置影响的。
在JumpingBeansSpan这个类中,最关键的代码应该是
@Override
public void updateMeasureState(TextPaint tp) {
initIfNecessary(tp.ascent());
tp.baselineShift = shift;
}
@Override
public void updateDrawState(TextPaint tp) {
initIfNecessary(tp.ascent());
tp.baselineShift = shift;
}
动画正是从这儿启动的,但是没有找到这两个方法调用时机,只是debug的时候可以debug到。
拆分文本的方法是在JumpingBeans这个类中
private JumpingBeansSpan[] buildWavingSpans(SpannableStringBuilder sbb) {
JumpingBeansSpan[] spans;
if (waveCharDelay == DEFAULT_WAVE_CHAR_DELAY) {
waveCharDelay = loopDuration / (3 * (endPos - startPos));
}
spans = new JumpingBeansSpan[endPos - startPos];
for (int pos = startPos; pos < endPos; pos++) {
JumpingBeansSpan jumpingBean =
new JumpingBeansSpan(textView, loopDuration, pos - startPos, waveCharDelay, animRange);
sbb.setSpan(jumpingBean, pos, pos + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spans[pos - startPos] = jumpingBean;
}
return spans;
}