如何在我的按钮启用的同时进行倒计时 show/start?

How do I make a CountDown show/start at the same moment my Button gets enabled?

"How do I make a CountDown show at the same moment my Button gets enabled ?"

有关按钮的其他信息:按钮作业是通过在 Textview 中显示的字符串数组单击 5 次,然后禁用 5 秒以再次执行相同的任务。

所以 ..我想要一个 CountDown 来直观地显示这 5 秒(启用按钮的时间)倒计时供用户查看。

遗憾的是,我不知道如何将我的 Button 与 CountDown 连接以让它知道它应该在 Button 启用的特定时间倒计时。

我还希望每次启用按钮时都启动倒计时。

我调查了 https://developer.android.com/reference/android/os/CountDownTimer 但它似乎没有针对该特定情况的解决方案。

这就是我现在的按钮代码:

next_button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if (currentnumber == list.length) {
                currentnumber = 0;
            }
            if (Curclicks == mod - 1) {
                next_button.setEnabled(false);
                display.setText(list[currentnumber]);
                currentnumber++;


                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //the button will unlock after the delay specified
                        next_button.setEnabled(true);
                        Curclicks = 0;

                    }
                }, delay);

            } else {
                display.setText(list[currentnumber]);
                currentnumber++;

            }
            Curclicks++;

        }

    });

UI线程代码能解决吗? :

  private void runThread() {

            new Thread() {
                public void run() {
                    while (delay == 5000) { //delay = 5000 ( 5 secs)
                        try {
                            runOnUiThread(new Runnable() {

                                @Override
                                public void run() {
                                    timer.setText("" + delay);//timer=TxtView
                                }
                            });
                            Thread.sleep(300);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();

这个函数应该做你想做的,只要调用它到 OnClickListener

public void countDown(Button yourBtn) {
    new Thread() {
        public void run() {
            try {
                int second = 10;
                for (int i = second; i >= 1; i--) {
                    int finalI = i;
                    yourBtn.post(new Runnable() {
                        @Override
                        public void run() {
                            yourBtn.setText(String.valueOf(finalI))
                        }
                    });
                    Thread.sleep(1000); // Change text every 1s
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }.start();
}

这是一个示例,说明如何使用 HandlerpostDelayed() 方法创建倒计时。我故意让代码有点冗长,这样你就可以一步一步地通过它来了解发生了什么。

创建一些 class 变量和常量。

private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();

COUNT_DOWN_FINISH 设置为 5000 --> 5 秒。但可以更改为您需要的任何内容。我还使用 COUNT_DOWN_TICKS 设置为 100 --> 0.1 秒,以防万一你想显示更精确的倒计时。

从您的 OnClick() 方法调用 startCountDown() 开始倒计时。

private void startCountDown() {
    try {
        countdownElapsed = 0l;
        next_button.setEnabled(false);
        displayCountDown();
        mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
    }
    catch (Exception ex){
        Log.e(TAG, ex.getMessage());
    }
}

private Runnable mCountDownRunnable = new Runnable() {
    @Override
    public void run() {
        countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;

        if(countdownElapsed >= COUNT_DOWN_FINISH){
            releaseCountDownHandler();
            next_button.setEnabled(true);
        }
        else{
            mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
        }

        long secFull = countdownElapsed % 1000;
        if(secFull == 0){
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    displayCountDown();
                }
            });
        }
    }
};

private void releaseCountDownHandler() {
    try {
        if(mCountDownRunnable != null) {
            mCountDownHandler.removeCallbacks(mCountDownRunnable);
        }
    }
    catch (Exception ex){
        Log.e(TAG, ex.getMessage());
    }
}


private void displayCountDown(){
    long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
    String myTime = String.valueOf(t);
    timer.setText(myTime);
}

为了正确处理 Runnable,您需要从 onPause() 方法中调用 releaseCountDownHandler()。这只是一个简短的运行Thread,但仍然不容忽视

Thread.sleep() 方法相比,我更喜欢使用 postDelay() 方法的 Handler -- 让任何线程进入休眠状态的做法令人不安。另请注意,习惯使用“>=”而不是“==”检查经过的时间条件是一个好主意,具体取决于实现(例如,您使用 SystemClock.elapsedRealtime() 代替)条件可能会错过确切的时间价值!


编辑


Activity class 定义的某处(在本例中我将其称为 MainActivity),您需要声明一些变量。由于它们是在 class 内部定义的,而不是在方法内部定义的,因此它们被称为 "class variables" 并且在定义 "private".[=36 时它们具有整个 class 的范围=]

public class MainActivity extends AppCompatActivity {

    //class variables
    private static final long COUNT_DOWN_TICKS = 100l;
    private static final long COUNT_DOWN_FINISH = 5000l;
    private long countdownElapsed = 0l;
    private Handler mCountDownHandler = new Handler();
    private Button next_button;
    private TextView timer;


....    

}

您可能已经在 MainActivity class 的 onCreate() 方法中声明了 onClick() 方法。所以只需添加以下代码:

next_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
    startCountDown();
}

我提供的所有其他内容都是 MainActivity class 中的方法...不在任何其他方法中。所以在 onCreate() 方法下面添加我之前发布的所有方法。

它将看起来像这样:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    //class variables
    private static final long COUNT_DOWN_TICKS = 100l;
    private static final long COUNT_DOWN_FINISH = 5000l;
    private long countdownElapsed = 0l;
    private Handler mCountDownHandler = new Handler();
    private Button next_button;
    private TextView timer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // you must compensate for the actual layout for your activity
        setContentView(R.layout.activity_main);


        // you must compensate for the actual id of the TextView
        timer = findViewById(R.id.tvTimer);

        // you must compensate for the actual id of the Button
        next_button = findViewById(R.id.btnNext);
        next_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startCountDown();
            }
        });
    }

    private void startCountDown() {
        try {
            countdownElapsed = 0l;
            next_button.setEnabled(false);
            displayCountDown();
            mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
        }
        catch (Exception ex){
            Log.e(TAG, ex.getMessage());
        }
    }

    private Runnable mCountDownRunnable = new Runnable() {
        @Override
        public void run() {
            countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;

            if(countdownElapsed >= COUNT_DOWN_FINISH){
                releaseCountDownHandler();
                next_button.setEnabled(true);
            }
            else{
                mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
            }

            long secFull = countdownElapsed % 1000;
            if(secFull == 0){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        displayCountDown();
                    }
                });
            }
        }
    };

    private void releaseCountDownHandler() {
        try {
            if(mCountDownRunnable != null) {
                mCountDownHandler.removeCallbacks(mCountDownRunnable);
            }
        }
        catch (Exception ex){
            Log.e(TAG, ex.getMessage());
        }
    }


    private void displayCountDown(){
        long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
        String myTime = String.valueOf(t);
        timer.setText(myTime); 
    }   

}

这段代码就像我上面的代码,只是这段代码引入了一个 "click counter"。我引入了一个新的 class 变量来跟踪按钮被点击的次数。我还引入了一个名为 "NUMBER_OF_BUTTON_CLICKS" 的新常量,它作为点击次数的上限。

用户现在可以点击按钮(在本例中)5 次。在第五次单击时,满足触发 startCountDown 方法的条件,按钮将禁用 5 秒。

public class MainActivity extends AppCompatActivity {
    //Constant values    
    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int NUMBER_OF_BUTTON_CLICKS = 5;
    private static final long COUNT_DOWN_TICKS = 100l;
    private static final long COUNT_DOWN_FINISH = 5000l;

    //class variables
    private int howManyClicks = 0;
    private long countdownElapsed = 0l;
    private Handler mCountDownHandler = new Handler();
    private Button next_button;
    private TextView timer;
    private TextView clicks;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // you must compensate for the actual layout for your activity
        setContentView(R.layout.activity_main);


        // you must compensate for the actual id of the TextView
        timer = findViewById(R.id.tvTimer);

        // Use this only if you want to display the number of clicks 
        // you might need to add this TextView if you want to display the number of clicks
        clicks = findViewById(R.id.tvClicks);

        // you must compensate for the actual id of the Button
        next_button = findViewById(R.id.btnNext);
        next_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                howManyClicks++;
                if(howManyClicks >= NUMBER_OF_BUTTON_CLICKS){
                    startCountDown();
                }

                //Add this only if you want to see how many clicks were made
                String myClicks = String.valueOf(howManyClicks);
                clicks.setText(myClicks)
            }
        });
    }

    private void startCountDown() {
        try {
            countdownElapsed = 0l;
            next_button.setEnabled(false);
            displayCountDown();
            mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
        }
        catch (Exception ex){
            Log.e(TAG, ex.getMessage());
        }
    }

    private Runnable mCountDownRunnable = new Runnable() {
        @Override
        public void run() {
            countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;

            if(countdownElapsed >= COUNT_DOWN_FINISH){
                releaseCountDownHandler();
                next_button.setEnabled(true);
                // reset the clicks counter
                howManyClicks = 0;
            }
            else{
                mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
            }

            long secFull = countdownElapsed % 1000;
            if(secFull == 0){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        displayCountDown();
                    }
                });
            }
        }
    };

    private void releaseCountDownHandler() {
        try {
            if(mCountDownRunnable != null) {
                mCountDownHandler.removeCallbacks(mCountDownRunnable);
            }
        }
        catch (Exception ex){
            Log.e(TAG, ex.getMessage());
        }
    }


    private void displayCountDown(){
        long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
        String myTime = String.valueOf(t);
        timer.setText(myTime);

        //Add this only if you want to see how many clicks were made
        String myClicks = String.valueOf(howManyClicks);
        clicks.setText(myClicks)
    }   

}