让你的Textview 跳跃起来
来源:互联网 发布:财务评价软件 编辑:程序博客网 时间:2024/05/17 20:34
直入主题!!!
在你的build.gradle 引入
compile 'com.android.support:support-annotations:23.1.1
android-support-annotations是Android官方提供的一个注解库,它提供了许多有用的注解,这些注解的生命周期为源码时期,也就是在编译之后则不再保留,通常用于辅助代码上的静态检查。但是如果你已经通过这种方式依赖了support-v4库的话,则不必再显式声明依赖它,因为support-v4也依赖于这个库,由于Gradle的传递依赖的特性,你的项目如果依赖了support-v4库的话,也会依赖到这个注解库。
详细介绍
http://blog.csdn.net/maosidiaoxian/article/details/50452706
使用
1.让 Jumping 跳跃起来
@Override protected void onResume() { super.onResume(); // those instead) final TextView textView1 = (TextView) findViewById(R.id.jumping_text_1); jumpingBeans1 = JumpingBeans.with(textView1) .appendJumpingDots() .build(); } @Override protected void onPause() { super.onPause(); jumpingBeans1.stopJumping(); jumpingBeans2.stopJumping(); }
2.让。。。跳跃起来
final TextView textView2 = (TextView) findViewById(R.id.jumping_text_2); jumpingBeans2 = JumpingBeans.with(textView2) .makeTextJump(0, textView2.getText().toString().indexOf(' ')) .setIsWave(false) .setLoopDuration(1000) .build();
功能Bean
1.JumpingBeans
public final class JumpingBeans { private static final String ELLIPSIS_GLYPH = "…"; private static final String THREE_DOTS_ELLIPSIS = "..."; private static final int THREE_DOTS_ELLIPSIS_LENGTH = 3; private final JumpingBeansSpan[] jumpingBeans; private final WeakReference<TextView> textView; private JumpingBeans(JumpingBeansSpan[] beans, TextView textView) { this.jumpingBeans = beans; this.textView = new WeakReference<>(textView); } /** * Create an instance of the {@link net.frakbot.jumpingbeans.JumpingBeans.Builder} * applied to the provided {@code TextView}. * * @param textView The TextView to apply the JumpingBeans to * @return the {@link net.frakbot.jumpingbeans.JumpingBeans.Builder} */ public static Builder with(@NonNull TextView textView) { return new Builder(textView); } /** * Stops the jumping animation and frees up the animations. */ public void stopJumping() { for (JumpingBeansSpan bean : jumpingBeans) { if (bean != null) { bean.teardown(); } } cleanupSpansFrom(textView.get()); } private static void cleanupSpansFrom(TextView textView) { if (textView == null) { return; } CharSequence text = textView.getText(); if (text instanceof Spanned) { CharSequence cleanText = removeJumpingBeansSpansFrom((Spanned) text); textView.setText(cleanText); } } private static CharSequence removeJumpingBeansSpansFrom(Spanned text) { SpannableStringBuilder sbb = new SpannableStringBuilder(text.toString()); Object[] spans = text.getSpans(0, text.length(), Object.class); for (Object span : spans) { if (!(span instanceof JumpingBeansSpan)) { sbb.setSpan(span, text.getSpanStart(span), text.getSpanEnd(span), text.getSpanFlags(span)); } } return sbb; } /** * Builder class for {@link net.frakbot.jumpingbeans.JumpingBeans} objects. * <p/> * Provides a way to set the fields of a {@link JumpingBeans} and generate * the desired jumping beans effect. With this builder you can easily append * a Hangouts-style trio of jumping suspension points to any TextView, or * apply the effect to any other subset of a TextView's text. * <p/> * <p>Example: * <p/> * <pre class="prettyprint"> * JumpingBeans jumpingBeans = JumpingBeans.with(myTextView) * .appendJumpingDots() * .setLoopDuration(1500) * .build(); * </pre> * * @see JumpingBeans#with(TextView) */ public static class Builder { private static final float DEFAULT_ANIMATION_DUTY_CYCLE = 0.65f; private static final int DEFAULT_LOOP_DURATION = 1300; // ms private static final int DEFAULT_WAVE_CHAR_DELAY = -1; private final TextView textView; private int startPos; private int endPos; private float animRange = DEFAULT_ANIMATION_DUTY_CYCLE; private int loopDuration = DEFAULT_LOOP_DURATION; private int waveCharDelay = DEFAULT_WAVE_CHAR_DELAY; private CharSequence text; private boolean wave; Builder(TextView textView) { this.textView = textView; } /** * Appends three jumping dots to the end of a TextView text. * <p/> * This implies that the animation will by default be a wave. * <p/> * If the TextView has no text, the resulting TextView text will * consist of the three dots only. * <p/> * The TextView text is cached to the current value at * this time and set again in the {@link #build()} method, so any * change to the TextView text done in the meantime will be lost. * This means that <b>you should do all changes to the TextView text * <i>before</i> you begin using this builder.</b> * <p/> * Call the {@link #build()} method once you're done to get the * resulting {@link net.frakbot.jumpingbeans.JumpingBeans}. * * @see #setIsWave(boolean) */ @NonNull public Builder appendJumpingDots() { CharSequence text = appendThreeDotsEllipsisTo(textView); this.text = text; this.wave = true; this.startPos = text.length() - THREE_DOTS_ELLIPSIS_LENGTH; this.endPos = text.length(); return this; } private static CharSequence appendThreeDotsEllipsisTo(TextView textView) { CharSequence text = getTextSafe(textView); if (text.length() > 0 && endsWithEllipsisGlyph(text)) { text = text.subSequence(0, text.length() - 1); } if (!endsWithThreeEllipsisDots(text)) { text = new SpannableStringBuilder(text).append(THREE_DOTS_ELLIPSIS); // Preserve spans in original text } return text; } private static CharSequence getTextSafe(TextView textView) { return !TextUtils.isEmpty(textView.getText()) ? textView.getText() : ""; } private static boolean endsWithEllipsisGlyph(CharSequence text) { CharSequence lastChar = text.subSequence(text.length() - 1, text.length()); return ELLIPSIS_GLYPH.equals(lastChar); } @SuppressWarnings("SimplifiableIfStatement") // For readability private static boolean endsWithThreeEllipsisDots(CharSequence text) { if (text.length() < THREE_DOTS_ELLIPSIS_LENGTH) { // TODO we should try to normalize "invalid" ellipsis (e.g., ".." or "....") return false; } CharSequence lastThreeChars = text.subSequence(text.length() - THREE_DOTS_ELLIPSIS_LENGTH, text.length()); return THREE_DOTS_ELLIPSIS.equals(lastThreeChars); } /** * Appends three jumping dots to the end of a TextView text. * <p/> * This implies that the animation will by default be a wave. * <p/> * If the TextView has no text, the resulting TextView text will * consist of the three dots only. * <p/> * The TextView text is cached to the current value at * this time and set again in the {@link #build()} method, so any * change to the TextView text done in the meantime will be lost. * This means that <b>you should do all changes to the TextView text * <i>before</i> you begin using this builder.</b> * <p/> * Call the {@link #build()} method once you're done to get the * resulting {@link net.frakbot.jumpingbeans.JumpingBeans}. * * @param startPos The position of the first character to animate * @param endPos The position after the one the animated range ends at * (just like in {@link String#substring(int)}) * @see #setIsWave(boolean) */ @NonNull public Builder makeTextJump(@IntRange(from = 0) int startPos, @IntRange(from = 0) int endPos) { CharSequence text = textView.getText(); ensureTextCanJump(startPos, endPos, text); this.text = text; this.wave = true; this.startPos = startPos; this.endPos = endPos; return this; } private static CharSequence ensureTextCanJump(int startPos, int endPos, CharSequence text) { if (text == null) { throw new NullPointerException("The textView text must not be null"); } if (endPos < startPos) { throw new IllegalArgumentException("The start position must be smaller than the end position"); } if (startPos < 0) { throw new IndexOutOfBoundsException("The start position must be non-negative"); } if (endPos > text.length()) { throw new IndexOutOfBoundsException("The end position must be smaller than the text length"); } return text; } /** * Sets the fraction of the animation loop time spent actually animating. * The rest of the time will be spent "resting". * * @param animatedRange The fraction of the animation loop time spent * actually animating the characters */ @NonNull public Builder setAnimatedDutyCycle(@FloatRange(from = 0f, to = 1f, fromInclusive = false) float animatedRange) { if (animatedRange <= 0f || animatedRange > 1f) { throw new IllegalArgumentException("The animated range must be in the (0, 1] range"); } this.animRange = animatedRange; return this; } /** * Sets the jumping loop duration. * * @param loopDuration The jumping animation loop duration, in milliseconds */ @NonNull public Builder setLoopDuration(@IntRange(from = 1) int loopDuration) { if (loopDuration < 1) { throw new IllegalArgumentException("The loop duration must be bigger than zero"); } this.loopDuration = loopDuration; return this; } /** * Sets the delay for starting the animation of every single dot over the * start of the previous one, in milliseconds. The default value is * the loop length divided by three times the number of character animated * by this instance of JumpingBeans. * <p/> * Only has a meaning when the animation is a wave. * * @param waveCharOffset The start delay for the animation of every single * character over the previous one, in milliseconds * @see #setIsWave(boolean) */ @NonNull public Builder setWavePerCharDelay(@IntRange(from = 0) int waveCharOffset) { if (waveCharOffset < 0) { throw new IllegalArgumentException("The wave char offset must be non-negative"); } this.waveCharDelay = waveCharOffset; return this; } /** * Sets a flag that determines if the characters will jump in a wave * (i.e., with a delay between each other) or all at the same * time. * * @param wave If true, the animation is going to be a wave; if * false, all characters will jump ay the same time * @see #setWavePerCharDelay(int) */ @NonNull public Builder setIsWave(boolean wave) { this.wave = wave; return this; } /** * Combine all of the options that have been set and return a new * {@link net.frakbot.jumpingbeans.JumpingBeans} instance. * <p/> * Remember to call the {@link #stopJumping()} method once you're done * using the JumpingBeans (that is, when you detach the TextView from * the view tree, you hide it, or the parent Activity/Fragment goes in * the paused status). This will allow to release the animations and * free up memory and CPU that would be otherwise wasted. */ @NonNull public JumpingBeans build() { SpannableStringBuilder sbb = new SpannableStringBuilder(text); JumpingBeansSpan[] spans; if (wave) { spans = buildWavingSpans(sbb); } else { spans = buildSingleSpan(sbb); } textView.setText(sbb); return new JumpingBeans(spans, textView); } @SuppressWarnings("Range") // Lint bug: the if makes sure waveCharDelay >= 0 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; } private JumpingBeansSpan[] buildSingleSpan(SpannableStringBuilder sbb) { JumpingBeansSpan[] spans; spans = new JumpingBeansSpan[]{new JumpingBeansSpan(textView, loopDuration, 0, 0, animRange)}; sbb.setSpan(spans[0], startPos, endPos, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spans; } }}
2 . JumpingBeansSpan
final class JumpingBeansSpan extends SuperscriptSpan implements ValueAnimator.AnimatorUpdateListener { private final WeakReference<TextView> textView; private final int delay; private final int loopDuration; private final float animatedRange; private int shift; private ValueAnimator jumpAnimator; public JumpingBeansSpan(@NonNull TextView textView, @IntRange(from = 1) int loopDuration, @IntRange(from = 0) int position, @IntRange(from = 0) int waveCharOffset, @FloatRange(from = 0, to = 1, fromInclusive = false) float animatedRange) { this.textView = new WeakReference<>(textView); this.delay = waveCharOffset * position; this.loopDuration = loopDuration; this.animatedRange = animatedRange; } @Override public void updateMeasureState(TextPaint tp) { initIfNecessary(tp.ascent()); tp.baselineShift = shift; } @Override public void updateDrawState(TextPaint tp) { initIfNecessary(tp.ascent()); tp.baselineShift = shift; } 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(); } @Override public void onAnimationUpdate(ValueAnimator animation) { // No need for synchronization as this always runs on main thread anyway TextView v = textView.get(); if (v != null) { updateAnimationFor(animation, v); } else { cleanupAndComplainAboutUserBeingAFool(); } } private void updateAnimationFor(ValueAnimator animation, TextView v) { if (isAttachedToHierarchy(v)) { shift = (int) animation.getAnimatedValue(); v.invalidate(); } } private static boolean isAttachedToHierarchy(View v) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return v.isAttachedToWindow(); } return v.getParent() != null; // Best-effort fallback (without adding support-v4 just for this...) } private void cleanupAndComplainAboutUserBeingAFool() { // The textview has been destroyed and teardown() hasn't been called teardown(); Log.w("JumpingBeans", "!!! Remember to call JumpingBeans.stopJumping() when appropriate !!!"); } public void teardown() { if (jumpAnimator != null) { jumpAnimator.cancel(); jumpAnimator.removeAllListeners(); } if (textView.get() != null) { textView.clear(); } } /** * 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); } }}
0 0
- 让你的Textview 跳跃起来
- 让你的TextView字体跳动起来
- 让你的Textview酷炫起来
- 让TextView滚动起来
- android让TextView滚起来
- 让你的网页文字动起来。。。
- 让你的电脑窗口绿起来
- 让你的对象活起来
- 让你的TreeView人性化起来
- 让你的系统盘空起来
- 让你的SWT程序运行起来
- 让你的博客赚起来
- 让你的照片"闪亮"起来
- 让你的图标动起来
- 让你的XAML运动起来
- 让你的linux下载快起来
- 让你的浏览器3D起来
- 让你的网页活跃起来
- Laravel新手教学视频
- Yii2.0 rules验证规则大全
- 深入理解JavaScript作用域和作用域链
- Android中的线程池ThreadPoolExecutor
- AngularJS系列——入门
- 让你的Textview 跳跃起来
- NGUI、UGUI、粒子间的渲染顺序解决方案
- NC工具的使用说明教程
- 51nod 2级算法题-1095
- 第1章信号完整性分析概论----基本定义和四类噪声问题
- 第五次上机作业
- 在系统里设置文件默认打开APP
- OpenGL鼠标交互
- CodeForces