Android 带有 Top/Down 动画的 TextView 计数器
Android TextView counter with Top/Down Animation
我们想要 TextView
中的 Meter 动画
为了让它更有趣一点,我希望每个数字从上到下或从下到上?
现在我使用 listview 来实现这个,我也尝试过 TextSwitcher
但它只有两个 child 的限制。
我正在使用 getListView().smoothScrollToPosition(0...3...6...6...n)
;
有没有简单的方法可以做到这一点?因为现在,我们需要维护 3 ListView
和 Adapter
以及维护这个。
请参阅link以更了解此问题
Display StopWatch Timer animated like the petrol pump meter using NSTimer
ListView
可能是足够好的解决方案,但我已经使用自定义视图 (FrameLayout
) 实现了它,其中包含 2 个 TextView
动画基于值变化:
代码思路很基础:
- 您传递给
setValue
想要的值;
- 如果它比当前值大 - 从下到上开始动画(反之亦然)到 increment/decrement 当前值加 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);
更新:
据我所知,另一种选择是设置一些自定义 NumberPicker
希望对您有所帮助!
您也可以使用处理程序来获得所需的效果。使用它,您不必制作任何自定义视图。
创建一个函数 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();
}
通过使用这种方法,我们不需要做任何数学运算。
自从 Robinhood 赢得 Material 设计大奖后,他们就开源了定制 TextView
的源代码,就像您描述的那样。
查看Robinhood's Ticker图书馆
此代码执行相同的动画,其中数字从上到下滚动。
我们想要 TextView
为了让它更有趣一点,我希望每个数字从上到下或从下到上?
现在我使用 listview 来实现这个,我也尝试过 TextSwitcher
但它只有两个 child 的限制。
我正在使用 getListView().smoothScrollToPosition(0...3...6...6...n)
;
有没有简单的方法可以做到这一点?因为现在,我们需要维护 3 ListView
和 Adapter
以及维护这个。
请参阅link以更了解此问题
Display StopWatch Timer animated like the petrol pump meter using NSTimer
ListView
可能是足够好的解决方案,但我已经使用自定义视图 (FrameLayout
) 实现了它,其中包含 2 个 TextView
动画基于值变化:
代码思路很基础:
- 您传递给
setValue
想要的值; - 如果它比当前值大 - 从下到上开始动画(反之亦然)到 increment/decrement 当前值加 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);
更新:
据我所知,另一种选择是设置一些自定义 NumberPicker
希望对您有所帮助!
您也可以使用处理程序来获得所需的效果。使用它,您不必制作任何自定义视图。 创建一个函数 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();
}
通过使用这种方法,我们不需要做任何数学运算。
自从 Robinhood 赢得 Material 设计大奖后,他们就开源了定制 TextView
的源代码,就像您描述的那样。
查看Robinhood's Ticker图书馆
此代码执行相同的动画,其中数字从上到下滚动。