【问题标题】:Animate number counter on custom view with for loop in onDraw method使用 onDraw 方法中的 for 循环在自定义视图上为数字计数器设置动画
【发布时间】:2025-11-25 10:15:01
【问题描述】:

我很困惑这是否是正确的做法。请纠正我。所以基本上我在我的自定义视图中使用canvas.drawText 方法绘制了一个文本。文本是一个数字(金额)。当事件发生时,我正在尝试使文本动画到另一个数字(例如:100 => 800)。

我知道这可以通过 onDraw 方法中的 for 循环计数器并调用 canvas.drawTextinvalidate() 来完成,直到达到最终数字。但是我的应用卡住了。

更新代码:

我已经更新了代码。现在应用程序不会卡住(根据 Simon 的建议)。但现在它只是一次性抽取所有数字(1-99)。 我不知道如何减慢循环速度

public class CustomView extends View implements OnTouchListener{

   private Canvas main_canvas;

   //...Other codes like, initialization, paint etc!...//

   @Override
   protected void onDraw(Canvas canvas) {
      main_canvas = canvas;
   }

   public boolean onTouch(View v, MotionEvent event) {
      switch(event.getAction()){
      case MotionEvent.ACTION_DOWN:
      //...Some action...//
      case MotionEvent.ACTION_MOVE:
      //...Some action...//
      case MotionEvent.ACTION_UP:
      runTextAnimation();
      }
   }

   private void runTextAnimation() {

        for(int i=1; i < 100; i++){
            main_canvas.drawText(String.valueOf(i), getMeasuredWidth()/2, 100, amountPaint);
            invalidate();
        }
   }

}

【问题讨论】:

    标签: android android-layout android-animation android-custom-view


    【解决方案1】:

    我通过使用 Runnable 并使用 postDelayed 将消息排队几毫秒来解决这个问题。尽管我必须感谢西蒙缩小了我的搜索范围和想法。下面是sn-p。希望这可以帮助某人。干杯。

        private Handler mHandler;
        private int i;
    
        mHandler.post(mUpdate); //call this to run
    
        private Runnable mUpdate = new Runnable() {
                   public void run() {
    
                    main_canvas.drawText("Secret Text"+i, getMeasuredWidth()/2, 50, textPaint);
    
                    i++; // incrementing the value
    
                    mHandler.postDelayed(this, 60);
                    invalidate();
                    }
            };
    

    顺便说一句,上面的 sn-p 是一个无限计数器,请注意在某个时候停止它。

    【讨论】:

      【解决方案2】:

      不要在 onDraw() 中使用 invalidate()!

      invalidate() 导致 onDraw() 被调用,然后你 invalidate() 导致 onDraw() 被调用,然后你 invalidate() - 你明白了。循环应该在 onDraw() 之外,并且您使用 invalidate 来更新视图。但请注意,如果您的循环太快,您可能看不到所有更新,因为更新已排队。

      让线程休眠一段时间:

      Thread.sleep(50);
      

      这会休眠 50 毫秒。试试吧,但我认为在 UI 线程上使用 Runnable 会是更好的解决方案。

      【讨论】:

      • 谢谢我试试看,有没有办法让循环减慢几微秒?
      • 你可以 sleep() 一段时间,但就个人而言,如果我发现自己正在考虑 sleep(),这会提示我考虑替代方案。
      • 亲爱的 simon,正如你所说,在 onDraw() 之外拨打 invalidate() 是正确的方法。这是有效的,应用程序不会卡住。但我对循环感到困惑并用线程运行它。你能更新一些提示或代码吗?基本上我在onTouch 事件MotionEvent.ACTION_UP 被触发后运行这个循环。希望我的解释清楚。提前致谢。
      • 请使用相关代码更新您的问题 - 即循环及其调用方式。为什么要使用单独的线程?我的猜测是你只是增加一个整数并更新你的视图。通过启动另一个线程,我看不到任何好处。
      • 我已经更新了我的答案,但是需要使用 sleep() 通常表明设计不好。让我知道它是否有效,然后我们可以考虑不同的方法?