桌面时钟APP的简单开发(Android开发)

开发目的

想打造个性化的私人闹钟APP,放到桌面上提示时间,但是感觉应用商店中的相关软件不好用,有些有广告,就难受。而且没有办法DIY自己想要的时钟样式。

所以,开搞!(初学者入门,慢慢摸索呗)

开发环境

1、windows操作系统

2、Android  Studio 2024

3、JDK 1.8(已配置的jdk环境,因为Android  Studio基于IntelliJ IDEA,需要jdk环境启动)

详细步骤

1、安装并搭建开发环境

Android  Studio工具下载官网

下载 Android Studio 和应用工具 - Android 开发者  |  Android Developers (google.cn)icon-default.png?t=N7T8https://developer.android.google.cn/studio?hl=zh-cn

按步骤安装即可,记得点上AVD,方便后续测试

下载SDK

2、创建工程

创建一个虚拟的手机视图(AVD)模拟器来方便我们开发

由于我使用的手机是MIUI13的版本,这里就用了Android 12来构建

项目下面可以有多个模块,编译运行app一般指的是运行某个模块

项目目录:

mainfests:下面有一个XML文件,是App的运行配置文件

kotlin+java:包含源代码、测试代码

res:资源文件,主要包括:drawable、layout、mipmap、values

Gradle Script主要包括工程编译配置文件,build-gradle是编译规则文件,分为全局配置和模块配置

3、创建XML文件(布局文件)

可以通过拖拽的方式添加组件了,右侧工具栏设置样式

点击右上角可以切换视图

先试着创建一个视图

要求显示一个居中显示的时钟、一个切换背景颜色的按钮,背景颜色默认为黑色

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootLayoutId"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:gravity="center"
    android:orientation="vertical">

    <TextClock
        android:id="@+id/textClock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Display1"
        android:textColor="#258729"
        android:textSize="200sp"
        android:textStyle="bold"
        android:typeface="normal" />

    <Button
        android:id="@+id/button2"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:onClick="onChangeBackgroundClick"
        android:text="@string/change" />
</LinearLayout>

在MainActivity中编写逻辑

package com.example.clock

import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun onChangeBackgroundClick(view: View) {
        // 找到布局
        val rootLayout = findViewById<LinearLayout>(R.id.rootLayoutId)
        // 设置背景颜色
        var backgroundDrawable = rootLayout.background
        val currentColor = (backgroundDrawable as ColorDrawable).color
        if (currentColor != -1) {
            rootLayout.setBackgroundColor(resources.getColor(R.color.white))
        } else {
            rootLayout.setBackgroundColor(resources.getColor(R.color.black))
        }
    }
}

效果:

记得调整时区为”Asia/Shanghai”

        var clock = findViewById<TextClock>(R.id.textClock)
        clock.timeZone = "Asia/Shanghai"

后续加入倒计时功能:

需要添加一个用户输入框用于输入倒计时长、和一个开始倒计时的确认框

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_vertical">
    <EditText
        android:id="@+id/inputEditText"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="48dp"
        android:autofillHints="5"
        android:ems="10"
        android:gravity="center"
        android:hint="Countdown  (minute)"
        android:textColor="#258729"
        android:textColorHint="#258729"
        android:inputType="text" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onStartCounting"
            android:text="@string/start" />
    </LinearLayout>

用<LinearLayout>标签将两元素框起,保证在同一水平行中

编写业务逻辑:

1、当用户输入内容在[1,999]之间,跳转到倒计时页面,传一个用户输入的时间参数过去,开始倒计时

2、若输入内容不符合规范,提示内容要在[1,999]之间,不跳转

这是一个函数,判断用户的“Start”行为,进行处理

    private fun getUserInput() {
        // 获取 EditText 的引用
        val inputEditText = findViewById<EditText>(R.id.inputEditText)

        // 获取用户输入的数据
        val userInput = inputEditText.text.toString() // 转换为 String

        if (userInput.matches("^[1-9][0-9]{0,2}\$".toRegex())) {
            // 匹配成功,准备跳转页面
            // 创建一个新的Intent,用于从当前Activity跳转到CountdownActivity
            val intent = Intent(this, CountdownActivity::class.java)

            // 可选:将用户输入作为额外信息传递给CountdownActivity
            // CountdownActivity有一个EXTRA_TIME的额外字符串字段来接收时间
            intent.putExtra("EXTRA_TIME", userInput)
            // 启动CountdownActivity
            startActivity(intent)
        } else {
            Toast.makeText(this, "Please enter a number between 0 and 999.", Toast.LENGTH_SHORT).show()
        }
    }

给按钮编写事件监听器

        val button = findViewById<Button>(R.id.buttonStart)
        button.setOnClickListener {
            getUserInput() // 当按钮被点击时调用此函数
        }

编写一个CountdownActivity 来实现倒计时模块

class CountdownActivity : AppCompatActivity() {
    private lateinit var timeTextView: TextView
    private var timeSeconds: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_countdown)

        // 获取从Intent中传递的额外数据
        val timeInput = intent.getStringExtra("EXTRA_TIME")?.toIntOrNull()
        timeSeconds = (timeInput?.times(60) ?: 0).toLong()
        timeTextView = findViewById(R.id.time)
        timeTextView.text = timeSeconds.toString()

        if (timeSeconds > 0) {
            // 使用协程来处理倒计时
            lifecycleScope.launch(Dispatchers.Main) {
                countdown()
            }
        }
    }

    private suspend fun countdown() {
        while (timeSeconds > 0) {
            delay(1000) // 暂停1秒钟
            timeSeconds--
            withContext(Dispatchers.Main) {
                // 更新UI必须在主线程
                timeTextView.text = timeSeconds.toString()
            }
        }
        // 倒计时结束后,启动MainActivity
        withContext(Dispatchers.Main) {
            val intent = Intent(this@CountdownActivity, MainActivity::class.java)
            startActivity(intent)
            finish() // 结束当前的CountdownActivity
        }
    }
}

显示页面包含倒计时时间以及豌豆射手贴图:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/countLayoutId"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/textview"
        android:textColor="#258729"
        android:textSize="150sp"
        android:textStyle="bold"/>

    <!-- 如果需要ImageView,可以添加以下属性 -->
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:contentDescription="@string/todo"
        app:srcCompat="@drawable/pp" />
</LinearLayout>

添加点击主页空白处隐藏(显示)按钮和输入框的功能,让页面简洁,方便显示

点击空白处的处理函数 以及 判断是否点击空白处的函数

    private fun onEmptySpaceClicked() {
        if (findViewById<Button>(R.id.buttonStart).isVisible) {
            findViewById<Button>(R.id.buttonStart).visibility = View.INVISIBLE;
            findViewById<Button>(R.id.buttonChange).visibility = View.INVISIBLE;
            findViewById<EditText>(R.id.inputEditText).visibility = View.INVISIBLE;
        } else {
            findViewById<Button>(R.id.buttonStart).visibility = View.VISIBLE;
            findViewById<Button>(R.id.buttonChange).visibility = View.VISIBLE;
            findViewById<EditText>(R.id.inputEditText).visibility = View.VISIBLE;
        }
    }
    private fun isClickOnView(rootView: View, targetView: View): Boolean {
        val location = IntArray(2)
        targetView.getLocationOnScreen(location)
        val x = rootView.x.toInt()
        val y = rootView.y.toInt()
        return location[0] in x until x + targetView.width && location[1] in y until y + targetView.height
    }

至此,V1.0版本已经完成! 期待后续添加更多自定义功能和样式!

错误日志

问题:

在应用试图使用与AppCompatActivity不兼容的样式或主题时发生

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. 指出你的Activity需要使用AppCompat主题或其派生主题。

解决:

设置主题,在AndroidManifest.xml设置主题为AppCompat的派生主题

            android:theme="@style/Theme.AppCompat.Light.NoActionBar">

问题:

跳转失败,无法跳转到目标Activity,直接闪退。

解决:

在AndroidManifest.xml中添加目标Activity的声明。

        <activity android:name=".CountdownActivity"
            android:exported="true"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        </activity>

问题:

apk包无法安装至手机上

解决:

首先要在gradle.properties中设置

android.injected.testOnly=false

其次,由于release版本的apk包才能在手机上运行,我们需要设置一个签名

选择打包为apk

create new

选择Release

成功安装!

问题:

项目没有横屏显示

解决:

<application>标签中设置android:screenOrientation属性:

    <application
        android:screenOrientation="landscape"

问题:

想让倒计时,每一秒刷新一次时间,利用Thread.sleep实现,但是应用直接被系统杀掉了

解决:

原因是在UI线程(主线程)进行了sleep的操作,这会导致应用程序的UI冻结

需要使用kotlin中提供的“协助线程”来解决

修改后代码如下

package com.example.clock

import android.content.Intent
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.*

class CountdownActivity : AppCompatActivity() {
    private lateinit var timeTextView: TextView
    private var timeSeconds: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_countdown)

        // 获取从Intent中传递的额外数据
        val timeInput = intent.getStringExtra("EXTRA_TIME")?.toIntOrNull()
        timeSeconds = (timeInput?.times(60) ?: 0).toLong()
        timeTextView = findViewById(R.id.time)
        timeTextView.text = timeSeconds.toString()

        if (timeSeconds > 0) {
            // 使用协程来处理倒计时
            lifecycleScope.launch(Dispatchers.Main) {
                countdown()
            }
        }
    }

    private suspend fun countdown() {
        while (timeSeconds > 0) {
            delay(1000) // 暂停1秒钟
            timeSeconds--
            withContext(Dispatchers.Main) {
                // 更新UI必须在主线程
                timeTextView.text = timeSeconds.toString()
            }
        }
        // 倒计时结束后,启动MainActivity
        withContext(Dispatchers.Main) {
            val intent = Intent(this@CountdownActivity, MainActivity::class.java)
            startActivity(intent)
            finish() // 结束当前的CountdownActivity
        }
    }
}

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开发一个时钟应用程序,你需要遵循以下步骤: 1. 创建一个新的 Android 项目。你可以使用 Android Studio 创建项目,选择“Empty Activity”模板。 2. 编写布局文件。你需要在布局中添加一个 TextView 控件来显示时间,并在布局中添加一些按钮来设置闹钟功能等。 3. 在 MainActivity 类中编写代码。你需要编写代码来获取当前时间,并更新 TextView 控件中的显示时间。同时,你还需要为按钮添加事件处理程序,例如设置闹钟。 4. 测试你的应用程序。你可以在模拟器或者真实设备上运行你的应用程序,检查是否正常工作。 下面是一个简单时钟应用程序的实现示例: 1. 在布局文件中添加一个 TextView 控件和一个 Button 控件: ``` <TextView android:id="@+id/textViewTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="40sp" /> <Button android:id="@+id/buttonSetAlarm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Set Alarm" /> ``` 2. 在 MainActivity 类中编写代码: ``` public class MainActivity extends AppCompatActivity { private TextView textViewTime; private Button buttonSetAlarm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textViewTime = findViewById(R.id.textViewTime); buttonSetAlarm = findViewById(R.id.buttonSetAlarm); // 获取当前时间并更新 TextView 控件 updateTime(); // 为按钮添加事件处理程序 buttonSetAlarm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setAlarm(); } }); } private void updateTime() { // 获取当前时间 Calendar calendar = Calendar.getInstance(); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); // 更新 TextView 控件 textViewTime.setText(String.format("%02d:%02d", hour, minute)); } private void setAlarm() { // TODO: 实现设置闹钟的功能 } } ``` 在 updateTime() 方法中,我们使用 Calendar 类获取当前时间,并使用 String.format() 方法将时间格式化为“HH:mm”的形式。在 setAlarm() 方法中,你可以实现设置闹钟的功能,例如弹出一个对话框供用户设置闹钟时间等。 这样,你就可以创建一个简单时钟应用程序了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值