尝试随时间设置值时,Android视图不会更新

时间:2017-03-02 08:42:03

标签: android android-animation android-runonuithread

我得到了一个片段,它有一个名为RingProgress的控件,它只是一个根据给定的百分比值填充自身的环。例如,如果我这样做:

ringProgress.setProgress(20);

这意味着现在将填充20%的戒指。

我正在尝试做的是在几秒钟内为正在填充的戒指设置动画。所以我试图做的是:

@Override
public void onResume()
{
    super.onResume();
    HandlerThread handlerThread = new HandlerThread("countdown");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable()
    {
        @Override
        public void run()
        {
            final Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask()
            {
                int totalSeconds = secondsToStart + minutesToStart * 60;
                int secondsPassed = 0;

                @Override
                public void run()
                {
                    if(secondsPassed == totalSeconds)
                    {
                        timer.cancel();
                    }
                    final int currentProgress = (secondsPassed / totalSeconds) * 100;
                    secondsPassed++;
                    getActivity().runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            mRingProgressBar.setProgress(currentProgress);
                        }
                    });

                }
            }, 0, 1000);

        }
    });
}

问题是直到时间到时才显示环的更新。例如,如果我将其设置为5秒,那么当片段加载时,环被设置为0,则5秒内没有任何事情发生,然后环完全100%全部一次...

如何正确启动此动画?

4 个答案:

答案 0 :(得分:3)

我猜问题是

final int currentProgress = (secondsPassed / totalSeconds) * 100;

secondsPassed / totalSeconds返回int值,因此它将仅为0或1。然后你将它乘以100。

您必须使用floatdouble代替

类似

final int currentProgress = Math.round(((float) secondsPassed)/((float) totalSeconds)*100f);

答案 1 :(得分:2)

在这一行:

Handler handler = new Handler(handlerThread.getLooper());

您正试图从handlerThread获取looper。但是你是如何确定你的looper已经被初始化了?

来自getLooper()

的文档
  

此方法返回与此线程关联的Looper。如果此线程未启动或isAlive()因任何原因返回false,则此方法将返回null。如果此线程已经启动,则此方法将阻塞,直到looper已初始化为止。

onLooperPrepared()是回调,您可以确定Looper已初始化,因此您可以构建逻辑。

因此,您需要做的是继承HandlerThread并从onLooperPrepared()回调创建适当的逻辑。

Here's a nice post会帮助你。请参阅那里MyWorkerThread类的实现。

答案 2 :(得分:1)

您可以使用属性动画器,而不是使用处理程序,如下所示:

ObjectAnimator.ofInt(mRingProgressBar, "progress", 0, 100)
    .setDuration(totalSeconds * 1000)   //time is in miliseconds
    .start();

这将在setProgress()中找到方法mRingProgressBar,并根据给定的限制设置值。在上面的示例中,0到100。 您可以阅读更多相关信息here

答案 3 :(得分:0)

由于您希望在不同的线程上运行,因此您可以在该类的顶部使用此处理程序:

     private int progress = 0;
     Handler timerHandler = new Handler();
     Runnable timerRunnable = new Runnable() {
            @Override
            public void run() {

            ringProgress.setProgress(progress);
            progress += 20;
            if (progress == 100) { //clear??
            }
            timerHandler.postDelayed(this, 1000);
        }
    };

inCreate设置最大值:

ringProgress.setMax(100);

这将在5秒内完成动画,然后您可以清除动画。如果您想要更小的增量,请更改下面的行(每十分之一秒更新一次),然后更改步骤

timerHandler.postDelayed(this, 100);