Android 开发第六弹:简易时钟(计时器)

接上篇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;
            }
        }
    };

结束

这是第二篇,还有一篇比较短的了……

需要代码的话,直接评论留邮箱吧,我就不上传到CSDN资源了。代码会继续更新的,注释也会继续更新……

项目也上传到Github了,欢迎大家贡献代码啊——传送门

版权声明:本文为 NoMasp柯于旺 原创文章,未经许可严禁转载!欢迎访问我的博客:http://blog.csdn.net/nomasp

时间: 2024-12-15 06:50:31

Android 开发第六弹:简易时钟(计时器)的相关文章

Android 开发第七弹:简易时钟(秒表)

本文承接,Android 开发第五弹:简易时钟(闹钟) 和 Android 开发第六弹:简易时钟(计时器),这一部分是关于秒表的. 布局 同样是新建一个类(StopWatchView)并扩展自LinearLayout,并将其用作布局. <myapplication.nomasp.com.clock.StopWatchView android : id = "@+id/tabStopWatch" android : layout_width = "match_parent

嵌入式Linux裸机开发(六)——S5PV210时钟系统

嵌入式Linux裸机开发(六)--S5PV210时钟系统 一.时钟系统简介 外设工作需要一定频率的时钟,这些时钟都由系统时钟提供.系统时钟一般由外部低频24MHZ晶体振荡器通过锁相环电路PLL倍频产生.通过外部的低频晶体振荡器产生系统时钟不仅可以减少干扰还可以降低成本.外设的工作频率越高,功耗越高,越不稳定.通过关闭外设的时钟可以关闭外设. 二.时钟域 S5PV210 中包含 3 大类时钟 domain, 分别是主系统时钟 domain (简称 MSYS).显示相关的时钟 domain (DSY

Android开发——本地验证码的简易实现(防止暴力登录)

0.  前言   验证码无处不在,有人问我,你知道达芬奇密码下面是什么吗,对,答案就是达芬奇验证码. 验证码一个最主要的作用就是防止恶意暴力破解登录,防止不间断的登录尝试,有人说其实可以在服务器端对该终端进行登录间隔检测,如果间隔太短可以展示拒绝的姿态.但是还是本地验证码作用更加实在,可以减轻服务器端的压力.这篇将使用自定义View来实现一个如下效果的简易本地验证码.算是对自定义View知识的复习吧. 1.  布局结构   <RelativeLayout xmlns:android="ht

Android 开发第三弹:自定义左右菜单(滑动动画+蒙版效果)

下面的截图--哎,因为1080P在Windows 10上虽然适配了,但大部分软件并没有跟上,比如某个录制GIF的软件,所以这里有一定的偏移导致画面不完整,但效果大概就是这么一个效果了. MainUI.java 首先需要这么一个类,在这里一些UI的滑动呀之类的都会定义.首先吧,定义好这些变量,当然了,实际开发过程中肯定需要哪一个就添加上哪一个的. private Context context; // 上下文 private FrameLayout leftMenu; // 左边部分 privat

简单的学习心得:网易云课堂Android开发第六章SQLite与ContentProvider

一.SQLite 1.基本操作: (1)创建数据库:在SQLiteOpenHelper的子类构造器中创建. (2)创建表:在SQLiteOpenHelper的子类onCreate方法中,调用execSQL方法实现. (3)增.删.改.查:分别调用SQLiteDatabase的insert.delete.update.query方法,又或者在execSQL方法中使用SQL语句来实现相应功能. 2.利用事务对数据库进行操作 (1)先开启事务db.beginTransaction(),接着执行操作 (

Android开发笔记(一百零六)支付缴费SDK

第三方支付 第三方支付指的是第三方平台与各银行签约,在买方与卖方之间实现中介担保,从而增强了支付交易的安全性.国内常用的支付平台主要是支付宝和微信支付,其中支付宝的市场份额为71.5%,微信支付的市场份额为15.99%,也就是说这两家垄断了八分之七的支付市场(2015年数据).除此之外,还有几个app开发会用到的支付平台,包括:银联支付,主要用于公共事业缴费,如水电煤.有线电视.移动电信等等的充值:易宝支付,主要用于各种报名考试的缴费,特别是公务员与事业单位招考:快钱,被万达收购,主要用于航空旅

Android开发实战之底部Dialog弹出效果

在Android开发中,有很多情况下我们需要使用到对话框,遗憾的是,安卓自带的对话框样式不能满足我们实际的需要,所以往往需要我们自定义对话框,具体做法:写一个对话框继承自Dialog实现他的一个构造方法(取决于你的用法),在OnCreate()中进行处理.当然更多情况下,你是不需要自己去写的,会抄代码一样也是一种本事,这里我介绍一种底部弹出的对话框,希望对你的学习和工作有所帮助,下面是效果图: 下面介绍具体做法: 导入依赖库: dependencies { compile 'com.github

android开发(31) 动画演示 - 从页面底部向上弹出dialog,消失时逐渐向下

我想实现一个效果,从底部向上逐渐弹出.如下图所示: 1.点击 显示 按钮时,一个dialog对话框从底部慢慢向上弹出. 2.关闭dialog时, dialog缓慢的移动向底部消失.很平滑的效果.     实现方式: 在activity中写代码如下 public class MainActivity extends Activity { Button button1; @Override protected void onCreate(Bundle savedInstanceState) { su

Android深度探索(卷1)HAL与驱动开发 第六章 第一个Linux驱动程序:统计单词个数

Android深度探索(卷1)HAL与驱动开发 第六章 第一个Linux驱动程序:统计单词个数 统计单词个数的功能是封装在Linux驱动中的. Linux驱动的工作和访问方式是Linux亮点之一,同时受到了业界大防范好评.Linux系统将每一个驱动都映射成一个文件.这些文件称为设备文件或者驱动文件,都保存在 /dev 目录中.这种设计理念使得与Linux驱动进行交互就像与普通文件进行交互一样容易.当然,也比访问Linux API 更容易.由于大多数Linux驱动都有与其对应的设备文件,因此与Li