带有上/下动画的Android TextView计数器

时间:2016-01-29 13:55:02

标签: android android-animation

我们有一个我想倒计时的TextView(9 ... 3 ... 2 ... 1 ... 0或0 ... 1 ... 3..6..9的东西发生)。

像这样(任何类型的仪表都在工作):

enter image description here

为了让它更有趣,我希望每个数字都是从上到下或从下到上?

现在我使用listview来实现这一点,我也试过了TextSwitcher,但它只限于两个孩子。

我正在使用getListView().smoothScrollToPosition(0...3...6...6...n);

有一种简单的方法吗?因为现在我们需要维持3 ListViewAdapter以维持这一点。

请参阅更多了解此问题的链接

Display StopWatch Timer animated like the petrol pump meter using NSTimer

4 个答案:

答案 0 :(得分:29)

ListView可能是一个很好的解决方案,但我已经使用自定义视图(FrameLayout)实现了它,其中包含2 TextView个内部,这是基于价值变化的动画:

enter image description here

代码的概念非常基础:

  • 您传递给setValue期望值;
  • 如果它比当前的大 - 从下到上开始动画(反之亦然),将当前值递增/递减1.在这里,我们动画两个TextView来互相替换;
  • 在AnimationEnd监听器中,检查我们是否达到了所需的值 - 如果没有 - 再运行一次(递归);

        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();
                }
            }
        }
    

它的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>

它非常易于使用:

添加到布局:

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

并在代码中设置值:

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

<强> UPD:
从我看到的另一个选择是设置一个自定义的NumberPicker

我希望,这有帮助!

答案 1 :(得分:6)

自Robinhood赢得材料设计奖以来,他们就像您所描述的那样开源于WaitForSingleObject

查看Robinhood's Ticker

enter image description here

答案 2 :(得分:2)

您还可以使用处理程序来获得所需的效果。使用此功能,您不必进行任何自定义视图。 创建一个函数 handleTextView ,它将 initialValue finalValue targetTextview 作为参数。方法是 -

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);
    }
  }

<强>更新 选项2-您也可以使用值动画 -

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();

}

通过使用这种方法,我们不需要做任何数学运算。

答案 3 :(得分:2)

此代码执行相同的动画,其中数字从上到下滚动。

Rolling-TextView-Animation

enter image description here