如何在Android中为textView创建一个计数效果

20

我正在开发一个应用程序,用于计算几段文本中问号的数量。

扫描完成后(这需要很短的时间),当数字从0变为总数时,我希望能够呈现出总数。因此,对于10:0、1、2、3、4、5、6、7、8、910,然后停止。

我已经尝试了一些不同的技术:

                TextView sentScore = (TextView) findViewById(R.id.sentScore);

                long freezeTime = SystemClock.uptimeMillis();

                for (int i = 0; i < sent; i++) {
                    if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
                        sentScore.setText(sent.toString());
                    }
                }

我也尝试了这个:

    for (int i = 0; i < sent; i++) { 
        // try {
            Thread.sleep(500);

        } catch (InterruptedException ie) {
            sentScore.setText(i.toString()); 
        } 
    }

我确定这两个尝试都是完全业余的。非常感谢任何帮助。

谢谢,

Richard


2
如果您正在UI线程上使用sleep方法,也就是应用程序的主线程,请不要这样做。它会阻塞界面,用户在此期间将无法执行任何操作。 - AndreiBogdan
那正是发生的事情。你有什么想法/建议可以帮我达到我期望的效果吗? - Richard Burton
这里已经很晚了,我很累所以无法完全理解你想要做什么,但为了避免界面冻结,你必须在一个单独的线程中设置睡眠方法。可以创建一个线程并将睡眠方法放在那里,或者我不确定是否有一种计时器,来自Java或Android平台,它会自动创建一个单独的线程,并且你可以附加一个回调函数,以便每500毫秒执行一次。只需搜索Java计时器或Android计时器,或者等待这里的某个人告诉你:P哈哈。我现在太累了 :) - AndreiBogdan
尝试使用此链接 https://github.com/uguratar/countingtextview - Kishan Vaghela
6个回答

61

我使用了更传统的Android风格动画:

        ValueAnimator animator = new ValueAnimator();
        animator.setObjectValues(0, count);
        animator.addUpdateListener(new AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setText(String.valueOf(animation.getAnimatedValue()));
            }
        });
        animator.setEvaluator(new TypeEvaluator<Integer>() {
            public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
                return Math.round(startValue + (endValue - startValue) * fraction);
            }
        });
        animator.setDuration(1000);
        animator.start();

你可以调整 0count 的数值,使计数器从任何一个数字到达另一个数字,并且你可以调整 1000 来设置整个动画的持续时间。
请注意,此功能支持 Android API 11 及以上版本,但您可以使用令人惊叹的 nineoldandroids 项目轻松实现向后兼容。

1
如果startValue不是0,它就不能正常工作。您必须更新evaluate函数以返回startValue +(endValue-startValue)* fraction。除此之外,做得很好! - Costi Muraru
它在double上如何工作?我收到了错误java.lang.ClassCastException:java.lang.Double无法转换为java.lang.Integer。 - Cliff
你需要将TypeEvaluator更改为TypeEvaluator<Float>,并从evaluate方法中返回一个浮点数。 - marmor

12

试一下这个:

private int counter = 0;
private int total = 30; // the total number
//...
//when you want to start the counting start the thread bellow.
    new Thread(new Runnable() {

                public void run() {
                    while (counter < total) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        t.post(new Runnable() {

                            public void run() {
                                t.setText("" + counter);

                            }

                        });
                        counter++;
                    }

                }

            }).start();

非常感谢您抽出时间编写这篇文章。目前我有一个获取文本消息并计算消息数量的方法,称为:protected void onActivityResult(int requestCode, int resultCode, Intent data) { 我想在此之后启动线程,还是在其中启动?如果我从该方法内部启动可运行线程,似乎无法使其正常工作。 - Richard Burton
2
@burtonic,从回调方法开始线程不应该有问题,当您获得总数时再开始线程。(onActivityResult是一个回调方法,当您希望从使用startActivityForResult()启动的子活动中获取某些内容时调用它)。请注意,TextView应该是final,这样您才能从匿名类中访问它。 - user
2
稍微调整一下,它就完全按照我的想法工作了。谢谢!http://cl.ly/0X0H0M1Y3Y3L1j3g1C2d - Richard Burton
使用Animator而不是直接处理它不是更好吗?我也读到过Thread很糟糕,对于Android最好使用Handler。 - HendraWD
@HendraWD 我的回答是在2012年发布的,显然当前的Animator类是更好的选择(看看marmor的回答)。Thread和Handler不是同一件事,所以我不明白你想要表达什么。 - user
@Luksprog 好的,感谢您的确认。是的,Thread和Handler是不同的东西,但Handler可以替代Thread。https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a www.mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler/ - HendraWD

4

2

使用TextSitcher可以获得最佳效果。它会使文本变得柔和。

在更改文本时,请使用以下代码。

> int number = 0;
>         Timer obj = new Timer();
>         TimerTask tt = new TimerTask() {
>                       @Override           public void run() {
>               // TODO Auto-generated method stub
>               textView.setText(number++);
>               if(number < score)
>               obj.schedule(tt, 200);          }       };
>         obj.schedule(tt, 200);

我相信你是指TextSwitcher,对吧?你应该发布一个更完整的代码片段来展示它的使用。但是,提到这个非常好的类还是值得赞扬的 :) - acrespo

1

使用工作线程来等待并更新您的 UI 线程。

您可以使用 AsyncTask,但这可能会对该工作过度。如果您使用它,在 doInBackground() 中循环睡眠周期的数量,并在每个睡眠周期后更新 UI 线程中的计数。

就是这样!Slukain 刚刚给出了可工作的代码 :P


0

也许尝试将for循环更改为以下内容:

int count = 0;
while (count != sent) {
    if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
        count++;
        sentScore.setText("" + count);
        freezeTime = SystemClock.uptimeMillis();
    }
}

不幸的是,这只会立即将正确的总数推送到视图中。我不得不将sentScore更改为sent。那是保存总数的变量的名称。 - Richard Burton
使用单独的线程和睡眠更好,正如slukian刚刚发布的那样。 - Jimbali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接