大概搜了一下關于文本跳躍的文章服协,思想大抵都是來自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;
}