Android自定义Chronometer实现短信验证码秒表倒计时功能

作者:FreedoMan 时间:2022-02-22 10:52:47 

本文实例为大家分享了Chronometer实现倒计时功能,Android提供了实现按照秒计时的API,供大家参考,具体内容如下

一、自定义ChronometerView 继续自TextView

主要原理:先设置一个基准倒计时时间mBaseSeconds,内置handler 每隔1s发送一个空消息,mRemainSeconds--,同时刷新界面视图,回调给外部调用者,只到为零。外部调用者可通过start()/pause()/stop()来控制计时器的工作状态。
可以app中发送短信验证码的场景为例,做了一个很粗糙的界面,但功能都实现了。

Android自定义Chronometer实现短信验证码秒表倒计时功能


/**
* @name 倒计时器(类似妙表倒数计时,支持暂停、停止、重新开始)
* @author Fanjb
* @date 2015年11月6日
*/
public class ChronometerView extends TextView {

/**
* A callback that notifies when the chronometer has decremented on its own.
*
* @author Fanjb
*/
public interface OnTickChangeListener {

/**
 * remain seconds changed
 *
 * @param view
 * @param remainSeconds
 */
public void onTickChanged(ChronometerView view, long remainSeconds);
}

private long mBase;
private long mRemainSeconds;
private boolean mStarted;
private boolean mReStart;
private boolean mVisible;
private boolean mIsEnable;

private OnTickChangeListener mTickListener;

public ChronometerView(Context context) {
this(context, null);
}

public ChronometerView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}

public ChronometerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
updateText(mRemainSeconds);
}

@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == VISIBLE;
updateStatus();
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mVisible = false;
updateStatus();
}

/**
* 启动计时器
*/
public void start() {
if (mReStart && !mStarted) {
 mRemainSeconds = mBase;
}
mStarted = true;
updateStatus();
}

/**
* 暂停计时器
*/
public void pause() {
if (mStarted) {
 mStarted = mReStart = false;
 updateStatus();
}
}

/**
* 停止计时器,再次调用 start()重新启动
*/
public void stop() {
mStarted = false;
mReStart = true;
updateStatus();
updateText(mRemainSeconds = 0);
dispatchTickListener();
}

/**
* 刷新内部状态
*/
private void updateStatus() {
boolean isEnable = mVisible && mStarted;
if (mIsEnable != isEnable) {
 if (isEnable) {
 mHandler.sendMessage(Message.obtain(mHandler, TICK_WHAT));
 } else {
 mHandler.removeMessages(TICK_WHAT);
 }
 mIsEnable = isEnable;
}
}

private static final int TICK_WHAT = 1;

private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
 if (mRemainSeconds > 0) {
 updateText(--mRemainSeconds);
 dispatchTickListener();
 sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);
 }
}
};

private void updateText(long now) {
String text = DateUtils.formatElapsedTime(now);
setText(text);
}

/**
* 在未启动状态下设置开始倒计时时间
*
* @param baseSeconds
*/
public void setBaseSeconds(long baseSeconds) {
if (baseSeconds > 0 && baseSeconds != mBase && !mStarted) {
 mBase = mRemainSeconds = baseSeconds;
 updateText(mRemainSeconds);
}
}

/**
* 剩余时间
*
* @return
*/
public long getRemainSeconds() {
return mRemainSeconds;
}

public void setOnTickChangeListener(OnTickChangeListener listener) {
mTickListener = listener;
}

public OnTickChangeListener getTickListener() {
return mTickListener;
}

private void dispatchTickListener() {
if (mTickListener != null) {
 mTickListener.onTickChanged(this, getRemainSeconds());
}
}

@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(ChronometerView.class.getName());
}

@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Chronometer.class.getName());
}
}

 二、xml 中没有加入自定义的控件属性,同TextView


<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<com.freedoman.widgets.calendar.ChronometerView
 android:id="@+id/chronometer_view"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:background="@drawable/chronometer_view_bg"
 android:enabled="true"
 android:text="00:00" />

<Button
 android:id="@+id/start_chronometer_view_btn"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="Start" />

<Button
 android:id="@+id/pause_chronometer_view_btn"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="Pause" />

<Button
 android:id="@+id/stop_chronometer_view_btn"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="Stop" />
</LinearLayout>

三、在Activity中做一个简单的测试(可以发送短信验证码的实际应用场景为例)


public class ChronometerActivity extends Activity {

private ChronometerView mChronometerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);

// 自定义计时器
if (mChronometerView == null) {
 mChronometerView = (ChronometerView) findViewById(R.id.chronometer_view);
 mChronometerView.setBaseSeconds(60);
 mChronometerView.setOnTickChangeListener(new OnTickChangeListener() {
 @Override
 public void onTickChanged(ChronometerView view, long curTimeMills) {
  System.out.println(curTimeMills);
  view.setEnabled(curTimeMills == 0 || curTimeMills == 60);
  if (curTimeMills == 0) {
  mChronometerView.setText("重新发送");
  }
 }
 });
 mChronometerView.setText("点击发送验证码");
}
findViewById(R.id.start_chronometer_view_btn).setOnClickListener(mClickListener);
findViewById(R.id.pause_chronometer_view_btn).setOnClickListener(mClickListener);
findViewById(R.id.stop_chronometer_view_btn).setOnClickListener(mClickListener);
}

private View.OnClickListener mClickListener = new OnClickListener() {

@Override
public void onClick(View v) {
 switch (v.getId()) {

case R.id.start_chronometer_view_btn:
 if (mChronometerView != null) {
  mChronometerView.start();
 }
 break;

case R.id.pause_chronometer_view_btn:
 if (mChronometerView != null) {
  mChronometerView.pause();
 }
 break;

case R.id.stop_chronometer_view_btn:
 if (mChronometerView != null) {
  mChronometerView.stop();
 }
 break;
 }
}
};
}
标签:Android,Chronometer,倒计时
0
投稿

猜你喜欢

  • Mybatis中resultMap的Colum和property属性详解

    2023-09-16 11:17:33
  • java实现二分法的完整代码

    2023-08-18 22:09:06
  • Spring MVC+FastJson+hibernate-validator整合的完整实例教程

    2021-10-31 13:20:13
  • ssm框架下web项目,web.xml配置文件的作用(详解)

    2021-07-31 14:42:11
  • 学习Winform文本类控件(Label、Button、TextBox)

    2022-12-29 09:00:48
  • SpringCloud微服务之Hystrix组件实现服务熔断的方法

    2021-12-04 16:30:45
  • Spring Boot配置AOP打印日志的全过程

    2023-08-07 12:56:38
  • android截屏功能实现代码

    2022-02-02 19:45:00
  • C#仿Windows XP自带的扫雷游戏

    2023-07-30 07:40:48
  • java中的控制结构(if,循环)详解

    2022-05-13 19:18:59
  • Java中实现简单的Excel导出

    2021-10-21 07:23:25
  • Java卡片布局管理器解释及实例

    2022-03-12 18:26:19
  • 详解maven中央仓库连不上的解决办法

    2023-02-25 08:43:54
  • java中sdk与jdk的区别详细解析

    2023-11-25 03:37:14
  • C#抓取网络图片保存到本地的实现方法

    2023-06-28 11:35:13
  • Android 6.0动态权限申请教程

    2023-09-26 16:43:56
  • 详解使用JRebel插件实现SpringBoot应用代码热加载

    2021-06-15 10:39:00
  • Android使用JobScheduler定期推送本地通知实例代码

    2023-07-26 22:43:28
  • Spring中自动注入的两种方式总结

    2022-10-24 08:54:14
  • Spring JPA 增加字段执行异常问题及解决

    2023-06-25 23:55:58
  • asp之家 软件编程 m.aspxhome.com