Android TextView counter with Top / Down animation

We have a TextView that I would like to list (9 ... 3 ... 2 ... 1 ... 0 or 0 ... 1 ... 3..6..9 happens).

Like this (how any counter works):

enter image description here

To make this a little more interesting, do I want each digit to be from top to bottom or from bottom to top?

Now I am using listview for this, I also tried with TextSwitcher , but it has a restriction on only two children.

I am using getListView().smoothScrollToPosition(0...3...6...6...n) ;

Is there an easy way to do this? because right now we need to support 3 ListView and Adapter , and also to support this.

Please refer to the link to understand this issue.

Display a StopWatch timer animated as a gas pump meter using NSTimer

+8
android android-animation
source share
4 answers

ListView may be a good enough solution, but I implemented it using a special view ( FrameLayout ), which contains 2 TextView s inside, which are animated based on value changes:

enter image description here

The idea of ​​the code is very simple:

  • You go to setValue desired value;
  • If it is larger than the current one, start the animation from the bottom up (and vice versa) to increase / decrease the current value by 1. Here we animate two TextView to replace each other;
  • In the AnimationEnd application, check if we have reached the desired value - if not, perform another run (recursively);

      public class DigitTextView extends FrameLayout { private static int ANIMATION_DURATION = 250; TextView currentTextView, nextTextView; public DigitTextView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public DigitTextView(Context context) { super(context); init(context); } private void init(Context context) { LayoutInflater.from(context).inflate(R.layout.digit_text_view, this); currentTextView = (TextView) getRootView().findViewById(R.id.currentTextView); nextTextView = (TextView) getRootView().findViewById(R.id.nextTextView); nextTextView.setTranslationY(getHeight()); setValue(0); } public void setValue(final int desiredValue) { if (currentTextView.getText() == null || currentTextView.getText().length() == 0) { currentTextView.setText(String.format(Locale.getDefault(), "%d", desiredValue)); } final int oldValue = Integer.parseInt(currentTextView.getText().toString()); if (oldValue > desiredValue) { nextTextView.setText(String.format(Locale.getDefault(), "%d", oldValue-1)); currentTextView.animate().translationY(-getHeight()).setDuration(ANIMATION_DURATION).start(); nextTextView.setTranslationY(nextTextView.getHeight()); nextTextView.animate().translationY(0).setDuration(ANIMATION_DURATION).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationEnd(Animator animation) { currentTextView.setText(String.format(Locale.getDefault(), "%d", oldValue - 1)); currentTextView.setTranslationY(0); if (oldValue - 1 != desiredValue) { setValue(desiredValue); } } @Override public void onAnimationCancel(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} }).start(); } else if (oldValue < desiredValue) { nextTextView.setText(String.format(Locale.getDefault(), "%d", oldValue+1)); currentTextView.animate().translationY(getHeight()).setDuration(ANIMATION_DURATION).start(); nextTextView.setTranslationY(-nextTextView.getHeight()); nextTextView.animate().translationY(0).setDuration(ANIMATION_DURATION).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationEnd(Animator animation) { currentTextView.setText(String.format(Locale.getDefault(), "%d", oldValue + 1)); currentTextView.setTranslationY(0); if (oldValue + 1 != desiredValue) { setValue(desiredValue); } } @Override public void onAnimationCancel(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} }).start(); } } } 

And this is XML:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="48dp" android:layout_height="56dp" android:padding="8dp" android:background="@drawable/rounded_blue_rect"> <TextView android:id="@+id/currentTextView" android:textColor="#FFFFFF" android:textSize="18sp" android:gravity="center" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/nextTextView" android:textColor="#FFFFFF" android:textSize="18sp" android:layout_gravity="center" android:gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </FrameLayout> 

And it is very easy to use:

Add to layout:

 <klogi.com.myapplication.DigitTextView android:id="@+id/digitTextView" android:layout_width="wrap_content" android:layout_height="wrap_content"/> 

And set the value in the code:

 DigitTextView digitTextView = (DigitTextView) findViewById(R.id.digitTextView); digitTextView.setValue(5); 

Upd:
Another use case, as I see it, is to set up a slightly customized NumberPicker

Hope this helps!

+29
source share

Since Robinhood won the Material design awards, they opened their own TextView as you describe.

Check out the Robinhood Ticker Library

enter image description here

+6
source share

You can also use a handler to get the desired effect. Using this, you do not have to create any custom views. Create a handleTextView function that takes initialValue , finalValue, and targetTextview as arguments. Method -

 private void handleTextView(int initialValue, int finalValue, final TextView targetTextview) { DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1f); final int newInitialValue = Math.min(initialValue, finalValue); final int newFinalValue = Math.max(initialValue, finalValue); final int difference = Math.abs(finalValue - initialValue); Handler handler = new Handler(); for (int count = newInitialValue; count <= newFinalValue; count++) { //Time to display the current value to the user. int time = Math.round(decelerateInterpolator.getInterpolation((((float) count) / difference)) * 100) * count; final int finalCount = ((initialValue > finalValue) ? initialValue - count : count); handler.postDelayed(new Runnable() { @Override public void run() { targetTextview.setText(finalCount.toString()); } }, time); } } 

UPDATE: Option 2. You can also use the value animator -

 private void handleTextView(int initialValue, int finalValue, final TextView textview) { ValueAnimator valueAnimator = ValueAnimator.ofInt(initialValue, finalValue); valueAnimator.setDuration(1500); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { textview.setText(valueAnimator.getAnimatedValue().toString()); } }); valueAnimator.start(); } 

Using this method, we do not need to do math.

+2
source share

This code performs the same animation where the number bounces from top to bottom.

Movable TextView Animation

enter image description here

0
source share

All Articles