Android 开发第六弹:简易时钟(计时器)
程序员文章站
2022-05-31 10:49:48
...
接上篇Android 开发第五弹:简易时钟(闹钟) ,这次是一个时钟类应用,目前依旧是主要的功能,长得还是很挫。当然了,核心功能是有的……
时钟
先把简单的时钟给列出来吧,这里都写的很简单,即便要用世界各个城市的话,也只是相应的加上或减去几个小时。
新建TimeView类,并扩展自LinearLayout,然后布局文件和上一篇中那么写就好了。
<myapplication.nomasp.com.clock.TimeView
android : id = "@+id/tabTime"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : orientation = "vertical">
<TextView
android : id = "@+id/tvTime"
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : gravity = "center" / >
</myapplication.nomasp.com.clock.TimeView>
// 实例化TextView控件
private TextView tvTime;
public TimeView(Context context) {
super(context);
}
public TimeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TimeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate(){
super.onFinishInflate();
tvTime = (TextView)findViewById(R.id.tvTime);
tvTime.setText("H");
timeHandler.sendEmptyMessage(0);
}
private Handler timeHandler = new Handler() {
public void handleMessage(Message msg){
// 刷新时间
refreshTime();
if(getVisibility() == View.VISIBLE){
timeHandler.sendEmptyMessageDelayed(0, 1000);
}
}
};
// 刷新时间
private void refreshTime(){
Calendar c = Calendar.getInstance();
// 试着显示的时间格式
tvTime.setText(String.format("%d:%d:%d",
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)));
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if(visibility == View.VISIBLE){
timeHandler.sendEmptyMessage(0);
}else{
timeHandler.removeMessages(0);
}
}
就这些了,下面正式开始计时器的部分。
TimerView
TimerView类同样是扩展自LinearLayout,并且布局的写法也是如出一辙:
<myapplication.nomasp.com.clock.TimerView
android : id = "@+id/tabTimer"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : orientation = "vertical">
<LinearLayout
android : orientation = "horizontal"
android : layout_width = "match_parent"
android : layout_height = "wrap_content">
<EditText
android : id = "@+id/etHour"
android : inputType = "number"
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : singleLine = "true" / >
android:singleLine = "true" / >
<TextView
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : text = ":" / >
<EditText
android : id = "@+id/etMinute"
android : inputType = "number"
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : singleLine = "true" / >
<TextView
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : text = ":" / >
<EditText
android : id = "@+id/etSecond"
android : inputType = "number"
android : textAppearance = "?android:attr/textAppearanceLarge"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : singleLine = "true" / >
< / LinearLayout>
<LinearLayout
android : id = "@+id/llBtnGroup"
android : layout_width = "match_parent"
android : layout_height = "wrap_content"
android : orientation = "horizontal">
<Button
android : id = "@+id/btnStart"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : text = "@string/start" / >
<Button
android : id = "@+id/btnPause"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : text = "@string/pause" / >
<Button
android : id = "@+id/btnResume"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : text = "@string/resume" / >
<Button
android : id = "@+id/btnReset"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : layout_weight = "1"
android : text = "@string/reset" / >
< / LinearLayout>
</myapplication.nomasp.com.clock.TimerView>
先把该定义的都定义好了:
private Button btnStart, btnPause, btnResume, btnReset;
private EditText etHour, etMinute, etSecond;
private static final int MSG_WHAT_TIME_IS_UP = 1;
private static final int MSG_WHAT_TIME_TICK = 2;
// 所有时间计数
private int allTimerCount = 0;
private Timer timer = new Timer();
private TimerTask timerTask = null;
public TimerView(Context context) {
super(context);
}
public TimerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TimerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
核心部分,首先给各个按钮设置监听,其中的点击分别实现相应的功能,并且设置相应的可见度,还要为每个EditText设置一个动态的判断,使其值不大于59也不小于0。
@Override
protected void onFinishInflate(){
super.onFinishInflate();
// 暂停
btnPause = (Button)findViewById(R.id.btnPause);
btnPause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.VISIBLE);
}
});
// 重置
btnReset = (Button)findViewById(R.id.btnReset);
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
etHour.setText("0");
etMinute.setText("0");
etSecond.setText("0");
btnReset.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
}
});
// 恢复
btnResume = (Button)findViewById(R.id.btnResume);
btnResume.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTime();
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
}
});
// 开始
btnStart = (Button)findViewById(R.id.btnStart);
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTime();
btnStart.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
btnReset.setVisibility(View.VISIBLE);
}
});
etHour = (EditText)findViewById(R.id.etHour);
etMinute = (EditText)findViewById(R.id.etMinute);
etSecond = (EditText)findViewById(R.id.etSecond);
// 对每一个EditText实例都作判断,值不可以大于59或小于0
etHour.setText("00");
etHour.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!TextUtils.isEmpty(s)) {
int value = Integer.parseInt(s.toString());
if (value > 59) {
etHour.setText("59");
} else if (value < 0) {
etHour.setText("0");
}
}
checkToEnableBtnStart();
}
@Override
public void afterTextChanged(Editable s) {
}
});
etMinute.setText("00");
etMinute.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!TextUtils.isEmpty(s)) {
int value = Integer.parseInt(s.toString());
if (value > 59) {
etMinute.setText("59");
} else if (value < 0) {
etMinute.setText("0");
}
}
checkToEnableBtnStart();
}
@Override
public void afterTextChanged(Editable s) {
}
});
etSecond.setText("00");
etSecond.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!TextUtils.isEmpty(s)){
int value = Integer.parseInt(s.toString());
if(value > 59){
etSecond.setText("59");
}else if(value < 0){
etSecond.setText("0");
}
}
checkToEnableBtnStart();
}
@Override
public void afterTextChanged(Editable s) {
}
});
btnStart.setVisibility(View.VISIBLE);
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnReset.setVisibility(View.GONE);
}
判断是否可以开始计数,每个输入框都不能小于等于0更不能为空。
// 判断是否可以开始
private void checkToEnableBtnStart(){
btnStart.setEnabled((!TextUtils.isEmpty(etHour.getText())
&& Integer.parseInt(etHour.getText().toString()) > 0) ||
(!TextUtils.isEmpty(etMinute.getText())
&& Integer.parseInt(etMinute.getText().toString()) > 0) ||
(!TextUtils.isEmpty(etSecond.getText())
&& Integer.parseInt(etSecond.getText().toString()) > 0));
}
接下来就可以开始计时了。
// 开始
private void startTime(){
if(timerTask == null){
// 从三个输入框中获取需要计数的总秒数
allTimerCount = Integer.parseInt(etHour.getText().toString())*60*60
+ Integer.parseInt(etMinute.getText().toString())*60
+ Integer.parseInt(etSecond.getText().toString());
timerTask = new TimerTask() {
@Override
// 执行计数,allTimerCount自减
public void run() {
allTimerCount-- ;
handler.sendEmptyMessage(MSG_WHAT_TIME_TICK);
// 如果剩下的所有计数已经小于0,通知handler停止
if(allTimerCount <= 0){
handler.sendEmptyMessage(MSG_WHAT_TIME_IS_UP);
stopTimer();
}
}
};
// 设置scedule,开始时间以及时间间隔,间隔此处为1秒
timer.schedule(timerTask,1000,1000);
}
}
当然除了开始计时外,也需要能够停止计时。
// 停止计时
private void stopTimer(){
if(timerTask != null){
timerTask.cancel();
timerTask = null;
}
}
接下来就是Handler了,也不算难,多写几遍就会了。
private Handler handler = new Handler() {
public void handleMessage(Message msg){
switch (msg.what){
case MSG_WHAT_TIME_TICK:
// 获取时间
int hour = allTimerCount/60/60;
int min = (allTimerCount/60)%60;
int sec = allTimerCount%60;
// 将时间写到对应的EditText上
etHour.setText(hour + "");
etMinute.setText(min + "");
etSecond.setText(sec + "");
break;
case MSG_WHAT_TIME_IS_UP:
// 弹出对话框进行提示,包括标题、消息、返回按钮
new AlertDialog.Builder(getContext()).setTitle("Time is up")
.setMessage("Message: Time is up")
.setNegativeButton("Cancel",null)
.show();
// 设置相应的可见与否
btnReset.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
break;
default:
break;
}
}
};
结束
这是第二篇,还有一篇比较短的了, Android 开发第七弹:简易时钟(秒表)……
需要代码的话,直接评论留邮箱吧,我就不上传到CSDN资源了。代码会继续更新的,注释也会继续更新……
项目也上传到Github了,欢迎大家贡献代码啊——传送门 。
上一篇: Java 简易计时器
下一篇: eclipse创建2dx项目