本文实例为大家分享了Android实战闹钟项目的具体代码,供大家参考,具体内容如下
一、闹钟功能的介绍以及界面的展示该闹钟是根据我们手机闹钟设计的一个简单的闹钟APP,其中包含时钟、闹钟、秒表和计时器功能。用户可以对闹钟添加和删除,可以对秒表计时、暂停和重置,对计时器可以暂停、计时、继续和重置等功能。
二、介绍系统的设计界面闹钟的布局文件代码如下
由于该闹钟系统包含时钟、闹钟、计时器、秒表四个功能,所以只要在xml文件插入TabHost控件就能实现在手机上更加简洁地展示四个功能。后面只需要在TabHost中插入四个Tab用来切换展示的界面,具体的代码实现如下:
public class MainActivity extends AppCompatActivity {
private TabHost mTabHost;
private StopWatchView mStopWatchView;
@Override
public SharedPreferences getPreferences(int mode) {
return super.getPreferences(mode);
}
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = (TabHost) findViewById(R.id.tabhost);
mTabHost.setup();
mTabHost.addTab(mTabHost.newTabSpec("tabTime").setIndicator("时钟").setContent(R.id.tabTime));
mTabHost.addTab(mTabHost.newTabSpec("tabAlarm").setIndicator("闹钟").setContent(R.id.tabAlarm));
mTabHost.addTab(mTabHost.newTabSpec("tabTimer").setIndicator("计时器").setContent(R.id.tabTimer));
mTabHost.addTab(mTabHost.newTabSpec("tabStopWatch").setIndicator("秒表").setContent(R.id.tabStopWatch));
mStopWatchView = (StopWatchView) findViewById(R.id.tabStopWatch);
}
@Override
protected void onDestroy() {
super.onDestroy();
mStopWatchView.onDestory();
}
}
一、时钟功能
因为时钟功能中,只要显示当前的日期和时钟就可以了,所以只需要插入一个TextView用来显示日期时间就可以了。
xml文件中的代码(new 一个时钟类TimeView,把时钟一块的LinearLayout换成com.example.tsclock.TimeView)
// 时钟
<com.example.tsclock.TimeView
android:id="@+id/tabTime"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvTime"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center"/>
</com.example.tsclock.TimeView>
TimeView.java
要将时间显示到TabHost中,就必须先要获取其中的id,然后通过Calendar获取当前系统的时间,最后再每过1秒钟刷新一次,这样就能够再TextView中出现时间在不停的变化。
public class TimeView extends LinearLayout {
private TextView tvTime;
public TimeView(Context context) {
super(context);
}
public TimeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TimeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// 在初始化之后进行的操作
@Override
protected void onFinishInflate() {
super.onFinishInflate();
tvTime = (TextView) findViewById(R.id.tvTime);
// handler每秒执行一次
timerHandler.sendEmptyMessage(0);
}
// 可见属性发生变化之后
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == View.VISIBLE){ // 如果可见 则发送一个消息
timerHandler.sendEmptyMessage(0);
}else{ // 如果不可见 移除所有的消息
timerHandler.removeMessages(0);
}
}
// 重新刷新时间
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)));
}
private Handler timerHandler = new Handler() {
public void handleMessage(android.os.Message msg){
// 呈现出来
refreshTime();
// 如果可见 则刷新
if (getVisibility() == View.VISIBLE){
// 1000毫秒之后再制学校handlerMessage()方法
timerHandler.sendEmptyMessageDelayed(0,1000);
}
}
};
}
二、闹钟功能
闹钟功能就相对时钟功能就复杂很多了,因为这里需要对闹钟进行增加,删除等操作,而且可能需要展示多个闹钟的时间。所以这里需要用到有一个Button控件用来增加闹钟和一个ListView控件用来展示闹钟的时间。
xml代码
// 闹钟
<com.example.tsclock.AlarmView
android:id="@+id/tabAlarm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/lvAlarmList"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
</ListView>
<Button
android:id="@+id/btnAddAlarm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add_alarm"
android:textColor="#FFFFFF"
android:background="@color/colorBlue" />
</com.example.tsclock.AlarmView>
闹钟类,AlarmView.java
需要判断时间到了需要触发事件,需要播放音乐和震动。所以播放音乐和震动放在另一个活动中(PlayAlarmAty.java )
public class AlarmView extends LinearLayout {
private Button btnAddAlarm;
private ListView lvAlarmList;
private ArrayAdapter<AlarmData> mAdapter;
private static final String KEY_ALARM_LIST = "alarmList";
// 使用系统的闹钟服务
private AlarmManager mAlarmManager;
public AlarmView(Context context) {
super(context);
init();
}
public AlarmView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
// 使用闹钟服务设定闹钟
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
}
// 在初始化之后进行的操作
@Override
protected void onFinishInflate() {
super.onFinishInflate();
btnAddAlarm = (Button)findViewById(R.id.btnAddAlarm);
lvAlarmList = (ListView) findViewById(R.id.lvAlarmList);
// 系统的简单资源
mAdapter = new ArrayAdapter<AlarmView.AlarmData>(getContext(),android.R.layout.simple_list_item_1);
// 设置Adapter
lvAlarmList.setAdapter(mAdapter);
// 读取已经存储在SharedPreferences中的数据
readSavedAlarmList();
btnAddAlarm.setOnClickListener(new View.OnClickListener() {// 添加闹钟的点击事件
@Override
public void onClick(View v) {
addAlarm();
}
});
// 删除闹钟
lvAlarmList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,final int position, long id) {
new AlertDialog.Builder(getContext()).setTitle("操作选项").setItems(new CharSequence[]{"删除"}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case 0:
deleteAlarm(position);
break;
default:
break;
}
}
}).setNegativeButton("取消",null).show();
return true;
}
});
}
// 删除闹钟
private void deleteAlarm(int position){
AlarmData ad = mAdapter.getItem(position);
// 把闹钟从闹钟列表移除
mAdapter.remove(ad);
saveAlarmList();
// 移除闹钟
mAlarmManager.cancel(PendingIntent.getBroadcast(getContext(),ad.getId(),new Intent(getContext(),AlarmReceiver.class),0));
}
// 添加闹钟
private void addAlarm(){
// 获取当前时间
Calendar c = Calendar.getInstance();
// 弹出一个时间的选择框
new TimePickerDialog(getContext(), new TimePickerDialog.OnTimeSetListener() {
// 设置时间
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// 获取当前时间
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,hourOfDay); // 设置时
calendar.set(Calendar.MINUTE,minute); // 设置分钟
calendar.set(Calendar.SECOND,0); // 秒清零
calendar.set(Calendar.MILLISECOND,0); // 毫秒值清零
// 如果设置闹钟时间小于当前时间,则往后推一天
Calendar currentTime = Calendar.getInstance();
if (calendar.getTimeInMillis() <= currentTime.getTimeInMillis()){
calendar.setTimeInMillis(calendar.getTimeInMillis()+24*60*60*1000);
}
AlarmData ad = new AlarmData(calendar.getTimeInMillis());
mAdapter.add(ad);
//需要根据API版本来判断调用,从Android4.4(API19)开始,为了节能省电(减少系统唤醒和电池使用)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mAlarmManager.setWindow(AlarmManager.RTC_WAKEUP,
ad.getTime(),
100, // 时间误差范围 100毫秒
PendingIntent.getBroadcast(getContext(), ad.getId(),
new Intent(getContext(), AlarmReceiver.class), 0));
} else {
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
ad.getTime(),
5*60*1000,
PendingIntent.getBroadcast(getContext(), ad.getId(),
new Intent(getContext(), AlarmReceiver.class), 0));
}
saveAlarmList();
}
},c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),true).show();
}
// 存储数据(存到SharedPreferences中)
private void saveAlarmList(){
SharedPreferences.Editor editor = getContext().getSharedPreferences(AlarmView.class.getName(),Context.MODE_PRIVATE).edit();
// 存储数据(for循环遍历Adapter)
StringBuffer sb = new StringBuffer();
//getCount表示这个adapter里面有多少item,就是有多少闹钟
for (int i = 0 ; i < mAdapter.getCount(); i++){
sb.append(mAdapter.getItem(i).getTime()).append(",");
}
// 所有的值传进去之后 去掉最后的逗
if (sb.length() > 1){
String content = sb.toString().substring(0,sb.length()-1);
editor.putString(KEY_ALARM_LIST,content);
System.out.println(content);// 输出存储的闹钟数据
}else {
editor.putString(KEY_ALARM_LIST,null);
}
editor.commit();
}
// 读取已存的数据
private void readSavedAlarmList(){
// 获取到SharedPreferences(数据内容)
SharedPreferences sp = getContext().getSharedPreferences(AlarmView.class.getName(),Context.MODE_PRIVATE);
String content = sp.getString(KEY_ALARM_LIST,null);
// 这里需要判断,不然没闹钟数据的时候会有空指针异常
if (content != null){
//这里取得每一个闹钟的time添加到数组里
String[] timeStrings = content.split(",");
// 遍历数组,把数据添加到mAdapter
for (String string : timeStrings){
mAdapter.add(new AlarmData(Long.parseLong(string)));
}
}
}
//闹钟的数据,用一个类要保存,这是常用的做法
private static class AlarmData{
private long time = 0;
private String timeLabel = ""; // 在外界获取时间的标签的字符串
private Calendar date;
// 闹钟响起的时间
public AlarmData(long time){
this.time = time;
date = Calendar.getInstance();
date.setTimeInMillis(time);
timeLabel = String.format("%d月%d日 %d:%d",
date.get(Calendar.MONTH)+1,
date.get(Calendar.DAY_OF_MONTH),
date.get(Calendar.HOUR_OF_DAY),
date.get(Calendar.MINUTE));
}
public AlarmData(String ad){
this.timeLabel = ad;
}
public void setTime(long time){
this.time = time;
}
public long getTime(){
return time;
}
public void setTimeLable(String timeLable){
this.timeLabel = timeLable;
}
@Override
public String toString() {
return getTimeLabel();
}
public String getTimeLabel() {
return timeLabel;
}
//为了给每一个闹钟设定一个标识,方便取消闹钟的使用能知道是哪一个闹钟
public int getId(){
return (int) (getTime()/1000/60);
}
}
}
当触发事件发生时,我们就要播放我们之前准备的音乐了,但是怎么播放呢,这里我们就要用到mediaPlayer媒体播放器这个函数了,这个函数主要就是用来播放音乐或者动画等。当开始播放时,我们也需要弹出警告框,提醒用户去关闭闹钟,所以这里我们需要另外编写一个类,用来执行这些功能。
PlayAlarmAty类中有播放音乐,开启震动,弹出关闭闹钟的dialog。
public class PlayAlarmAty extends Activity {
// 音乐播放器
private MediaPlayer mMediaPlayer;
private Vibrator vibrator;
private PowerManager.WakeLock mWakelock;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); // hide title
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
winParams.flags |= (WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
// 播放闹钟铃声
mMediaPlayer = MediaPlayer.create(this,R.raw.music); //使用create方式,创建MediaPlayer对象
mMediaPlayer.setLooping(true); // 设置是否对播放的音乐进行循环播放
mMediaPlayer.start();
startVibrator();
createDialog();
}
@Override
protected void onPause() {
super.onPause();
finish();
// 释放锁屏
releaseWakeLock();
}
@Override
protected void onResume() {
super.onResume();
// 唤醒屏幕
acquireWakeLock();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMediaPlayer.stop();
mMediaPlayer.release(); // 释放掉
}
// 唤醒屏幕
private void acquireWakeLock() {
if (mWakelock == null) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakelock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_DIM_WAKE_LOCK, this.getClass()
.getCanonicalName());
mWakelock.acquire();
}
}
// 释放锁屏
private void releaseWakeLock() {
if (mWakelock != null && mWakelock.isHeld()) {
mWakelock.release();
mWakelock = null;
}
}
// 震动
private void startVibrator() {
// 想设置震动大小可以通过改变pattern来设定,如果开启时间太短,震动效果可能感觉不到
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = { 500, 1000, 500, 1000 }; // 停止 开启 停止 开启
vibrator.vibrate(pattern, 0);
}
private void createDialog() {
new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_clock)
.setTitle("闹钟")
.setMessage("闹钟时间到了!!!")
.setPositiveButton("推迟10分钟", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
tenMRemind();
mMediaPlayer.stop();
vibrator.cancel();
finish();
}
})
.setNegativeButton("关闭", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mMediaPlayer.stop();
vibrator.cancel();
finish();
}
}).create().show();
}
// 推迟10分钟提醒
private void tenMRemind(){
//设置时间
Calendar calendar_now = Calendar.getInstance();
calendar_now.setTimeInMillis(System.currentTimeMillis());
calendar_now.set(Calendar.HOUR_OF_DAY, calendar_now.get(Calendar.HOUR_OF_DAY));
calendar_now.set(Calendar.MINUTE, calendar_now.get(Calendar.MINUTE)+10);
calendar_now.set(Calendar.SECOND, 0);
calendar_now.set(Calendar.MILLISECOND, 0);
//时间选择好了
Intent intent = new Intent(this, AlarmReceiver.class);
//注册闹钟广播
PendingIntent sender = PendingIntent.getBroadcast(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am;
am = (AlarmManager) this.getSystemService(this.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar_now.getTimeInMillis(), sender);
}
}
但是要当时间到了启动这个活动,就需要一个接收器,接受这个事件,所以有需要另一个类AlarmReceiver。
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("闹钟执行了");
// 闹钟执行一次就取消当前所执行的闹钟
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// 取消闹钟
am.cancel(PendingIntent.getBroadcast(context,getResultCode(),new Intent(context,AlarmReceiver.class),0));
Intent i = new Intent(context,PlayAlarmAty.class); // 要启动的类
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 设置启动的模式
context.startActivity(i);
}
}
三、秒表功能
秒表功能包含四个功能键,分别为开始,暂停、继续和重置。所以需要四个Button,然后需要三个EditText分别用来给用户输入时分秒。具体的xml代码如下:
// 秒表
<com.example.tsclock.StopWatchView
android:id="@+id/tabStopWatch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/timeHour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=":"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:id="@+id/timeMin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=":"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:id="@+id/timeSec"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="."
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:id="@+id/timeMSec"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<ListView
android:id="@+id/lvWatchTime"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnSWStart"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/start"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnSWPause"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/pause"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnSWResume"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/resume"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnSWLap"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/lap"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnSWReset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/reset"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
</LinearLayout>
</com.example.tsclock.StopWatchView>
在秒表功能中,含有四个Button,但是有时候只要显示一个或者是两个其余的就需要隐藏,所以这里就需要用到Button中的属性setVisibility(View.GONE)或者是setVisibility(View.VISIBLE),这是用来隐藏和显示Button。
有时候我们需要考虑系统的健壮性,比如当我们输入大于59的数或者是小于0的数,这时候我们需要系统检测出来,并进行修正。
需要注意的就是,当我们修改计时的时间的时候,当我们不小心将数目清空的时候,这时候就会将空指针上传,导致系统的崩溃,所以我们需要判断是不是空指针,防止越界报错。
该秒表功能有五个Button,所以需要对每个Button添加触发事件,其实startTime()函数的功能为开始计时,stopTime()函数的功能为暂停计时。所以这里需要弄清楚的就是什么时候该让那些按钮隐藏,什么时候该让那些按钮显示。
public class StopWatchView extends LinearLayout {
private TextView tvHour,tvMin,tvSec,tvMSec;
private Button btnSWStart,btnSWResume,btnSWReset,btnSWLap,btnSWPause;
private ListView lvTimeList;
private ArrayAdapter<String> adapter;
private Timer mTimer = new Timer();
private TimerTask mTimerTask = null;
private int tenMSec = 0;
private TimerTask showTimerTask = null;
private static final int MSG_WHAT_SHOW_TIME = 1;
public StopWatchView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
tvHour = (TextView) findViewById(R.id.timeHour);
tvHour.setText("0");
tvMin = (TextView) findViewById(R.id.timeMin);
tvMin.setText("0");
tvSec = (TextView) findViewById(R.id.timeSec);
tvSec.setText("0");
tvMSec = (TextView) findViewById(R.id.timeMSec);
tvMSec.setText("0");
// 计时
btnSWLap = (Button) findViewById(R.id.btnSWLap);
btnSWLap.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 时 分 秒 毫秒
adapter.insert(String.format("%d:%d:%d.%d",tenMSec/100/60/60,tenMSec/100/60%60,tenMSec/100%60,tenMSec%100),0);
}
});
// 开始
btnSWStart = (Button) findViewById(R.id.btnSWStart);
btnSWStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnSWStart.setVisibility(View.GONE);
btnSWPause.setVisibility(View.VISIBLE);
btnSWLap.setVisibility(View.VISIBLE);
}
});
// 暂停
btnSWPause = (Button) findViewById(R.id.btnSWPause);
btnSWPause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
btnSWPause.setVisibility(View.GONE);
btnSWResume.setVisibility(View.VISIBLE);
btnSWLap.setVisibility(View.GONE);
btnSWReset.setVisibility(View.VISIBLE);
}
});
// 继续
btnSWResume = (Button) findViewById(R.id.btnSWResume);
btnSWResume.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnSWResume.setVisibility(View.GONE);
btnSWPause.setVisibility(View.VISIBLE);
btnSWReset.setVisibility(View.GONE);
btnSWLap.setVisibility(View.VISIBLE);
}
});
// 重置
btnSWReset = (Button) findViewById(R.id.btnSWReset);
btnSWReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
tenMSec = 0;
adapter.clear();// 重置需要清除列表
btnSWLap.setVisibility(View.GONE);
btnSWPause.setVisibility(View.GONE);
btnSWResume.setVisibility(View.GONE);
btnSWReset.setVisibility(View.GONE);
btnSWStart.setVisibility(View.VISIBLE);
}
});
// 设置除了开始之外 其它四个按钮不可见
btnSWLap.setVisibility(View.GONE);
btnSWPause.setVisibility(View.GONE);
btnSWResume.setVisibility(View.GONE);
btnSWReset.setVisibility(View.GONE);
lvTimeList = (ListView) findViewById(R.id.lvWatchTime);
// 初始化话adapter
adapter = new ArrayAdapter<String>(getContext(),android.R.layout.simple_list_item_1);
lvTimeList.setAdapter(adapter);
// 使用showTimerTask不断执行刷新的操作
showTimerTask = new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(MSG_WHAT_SHOW_TIME);
}
};
mTimer.schedule(showTimerTask,200,200); // 一秒钟刷新五次
}
private void startTimer(){
if (mTimerTask == null){
mTimerTask = new TimerTask() {// 计时的timerTask
@Override
public void run() {
tenMSec++;
}
};
mTimer.schedule(mTimerTask,10,10); // 每隔十毫秒执行一次
}
}
private void stopTimer(){
if (mTimerTask != null){
mTimerTask.cancel();
mTimerTask = null;
}
}
// 呈现时间的handler
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MSG_WHAT_SHOW_TIME:
tvHour.setText(tenMSec/100/60/60+""); // 时
tvMin.setText(tenMSec/100/60%60+""); // 分
tvSec.setText(tenMSec/100%60+""); // 秒
tvMSec.setText(tenMSec%100+""); // 毫秒
break;
default:
break;
}
}
};
public void onDestory() {
mTimer.cancel();
}
}
四、计时器功能
这个和上面讲了秒表比较类似,不同的是多一个Button按钮用来计时,还多一个EditView(毫秒值),另外还需要一个ListView用来显示计时的时间,详细的xml代码如下:
// 计时器
<com.example.tsclock.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="0dp"
android:layout_weight="1">
<EditText
android:id="@+id/etHour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="number"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=":"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<EditText
android:id="@+id/etMin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="number"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=":"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<EditText
android:id="@+id/etSec"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="number"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:id="@+id/btnGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnStart"
android:layout_width="0dp"
android:text="@string/start"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnPause"
android:layout_width="0dp"
android:text="@string/pause"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnResume"
android:layout_width="0dp"
android:text="@string/resume"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
<Button
android:id="@+id/btnReset"
android:layout_width="0dp"
android:text="@string/reset"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#FFFFFF"
android:background="@color/colorBlue"/>
</LinearLayout>
</com.example.tsclock.TimerView>
计时器功能和秒表功能差不多
public class TimerView extends LinearLayout {
private Button btnStart,btnPause,btnResume,btnReset;
private EditText etHour,etMin,etSec;
private Timer mTimer = new Timer(); // 计时器
private TimerTask mTimerTask = null;
private int allTimerCount = 0;
private static final int MSG_WHAT_TIME_IS_UP = 1;
private static final int MSG_WHAT_TIME_IS_TICK = 2; // 时钟一格一格的往下走
private ListView mListView;
public TimerView(Context context) {
super(context);
}
public TimerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//开始
btnStart = (Button) findViewById(R.id.btnStart);
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnStart.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
btnReset.setVisibility(View.VISIBLE);
etHour.setEnabled(false);
etMin.setEnabled(false);
etSec.setEnabled(false);
}
});
// 暂停
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);
}
});
// 继续
btnResume = (Button) findViewById(R.id.btnResume);
btnResume.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
}
});
// 重置
btnReset = (Button) findViewById(R.id.btnReset);
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
etHour.setText("00");
etMin.setText("00");
etSec.setText("00");
etHour.setEnabled(true);
etMin.setEnabled(true);
etSec.setEnabled(true);
btnStart.setVisibility(View.VISIBLE);
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnReset.setVisibility(View.GONE);
}
});
etHour = (EditText) findViewById(R.id.etHour);
etMin = (EditText) findViewById(R.id.etMin);
etSec = (EditText) findViewById(R.id.etSec);
etHour.setText("00");
// 添加事件监听器
etHour.addTextChangedListener(new TextWatcher() {
@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 beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
etMin.setText("00");
etMin.addTextChangedListener(new TextWatcher() {
@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){
etMin.setText("59");
}else if (value < 0){
etMin.setText("0");
}
}
checkToEnableBtnStart();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
etSec.setText("00");
etSec.addTextChangedListener(new TextWatcher() {
@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){
etSec.setText("59");
}else if (value < 0){
etSec.setText("0");
}
}
checkToEnableBtnStart();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
btnStart.setVisibility(View.VISIBLE); // 设置开始可见
btnStart.setEnabled(false); // 不可点击(开始还没有设置时间)
btnPause.setVisibility(View.GONE); // 设置暂停不可见
btnResume.setVisibility(View.GONE);
btnReset.setVisibility(View.GONE);
}
private void checkToEnableBtnStart(){
btnStart.setEnabled((!TextUtils.isEmpty(etHour.getText()) && Integer.parseInt(etHour.getText().toString()) > 0) ||
(!TextUtils.isEmpty(etMin.getText()) &&Integer.parseInt(etMin.getText().toString()) > 0) ||
(!TextUtils.isEmpty(etSec.getText()) &&Integer.parseInt(etSec.getText().toString()) > 0));
}
private void startTimer(){
if (mTimerTask == null){
// 所使用时间的计数
allTimerCount = Integer.parseInt(etHour.getText().toString())*60*60+Integer.parseInt(etMin.getText().toString())*60+Integer.parseInt(etSec.getText().toString());
mTimerTask = new TimerTask() {
@Override
public void run() { // run方法会被mTimer执行
// 每执行一次 计数减一
allTimerCount--;
// 获取到当
mHandler.sendEmptyMessage(MSG_WHAT_TIME_IS_TICK);
if (allTimerCount <= 0){
// 访问mHandler
mHandler.sendEmptyMessage(MSG_WHAT_TIME_IS_UP);
stopTimer();
}
}
};
mTimer.schedule(mTimerTask,1000,1000); // run方法每隔一秒执行一次
}
}
private void stopTimer(){
if (mTimerTask != null){
mTimerTask.cancel();
mTimerTask = null;
}
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MSG_WHAT_TIME_IS_TICK:
int hour = allTimerCount/60/60;
int min = (allTimerCount/60)%60;
int sec = allTimerCount%60;
etHour.setText(hour+"");
etMin.setText(min+"");
etSec.setText(sec+"");
break;
case MSG_WHAT_TIME_IS_UP:
// 执行弹出对话框操作
// 把时间停止(弹出一个对话框)
new AlertDialog.Builder(getContext()).setTitle("时间到了!!!").setNegativeButton("退出",null).show();
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnReset.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
etHour.setEnabled(true);
etMin.setEnabled(true);
etSec.setEnabled(true);
break;
default:
break;
}
}
};
}