首页 > 其他分享 >桌面时钟APP的简单开发(Android开发)

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

时间:2024-06-22 22:30:23浏览次数:11  
标签:findViewById val import APP 开发 CountdownActivity timeSeconds Android id

开发目的

想打造个性化的私人闹钟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
        }
    }
}

标签:findViewById,val,import,APP,开发,CountdownActivity,timeSeconds,Android,id
From: https://blog.csdn.net/ddfhfjd/article/details/139848827

相关文章

  • 基于SpringBoot+Vue+uniapp的点餐系统的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的微信小程序书店的详细设计和实现(源码+lw+部署文档+讲解
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的懂球短视频微信小程序的详细设计和实现(源码+lw+部署文档
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • Linux开发讲课9--- Linux的IPC机制-内存映射(Memory Mapping)
            Linux的IPC(Inter-ProcessCommunication,进程间通信)机制是多个进程之间相互沟通的方法,它允许不同进程之间传播或交换信息。Linux支持多种IPC方式,包括但不限于:管道(Pipe):包括无名管道和命名管道(FIFO)。无名管道是半双工的,通常用于具有亲缘关系的进程间通信,如父子......
  • Linux开发讲课10--- Linux软中断
    中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求。你可能要问了,为什么要有中断呢?我可以举个生活中的例子,让你感受一下中断的魅力。比如说你订了一份外卖,但是不确定外卖什么时候送到,也没有别的方法了解外......
  • 02 uniapp项目基础配置
    引入uni-ui组件库1.安装pnpmi@dcloudio/uni-ui2.配置自动导入组件pages.json文件//组件自动导入"easycom":{"autoscan":true,"custom":{//uni-ui规则如下配置//[!code++]"^uni-(.*)":"@dcloudio/uni-ui/......
  • 深入PHP框架开发:实现高效的日志记录系统
    在软件工程中,日志记录是一种记录程序运行时发生事件的实践,它对于调试、监控和安全分析至关重要。PHP框架提供了多种方式来实现日志记录,这些方式可以帮助开发者捕获和存储关键信息。本文将详细探讨在PHP框架中实现日志记录的不同策略和技术。日志记录的基本概念在深入探讨......
  • Android面试题:App性能优化之Java和Kotlin常见的数据结构
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点Java常见数据结构特点ArrayListArrayList底层是基于数组实现add、删除元素需要进行元素位移耗性能,但查找和修改块适合不需要频繁添加删除的链表LinkedList是双......
  • 【需求管理】软件需求开发和管理文档(原件Word)
     1.目的2.适用范围3.参考文件4.术语和缩写5.需求获取的方式5.1.与用户交谈向用户提问题5.1.1.访谈重点注意事项5.1.2.访谈指南5.2.参观用户的工作流程5.3.向用户群体发调查问卷5.4.已有软件系统调研5.5.资料收集5.6.原型系统调研5.6.......
  • 尚玩助手app对接广告模式开发源码搭建
    当涉及到“尚玩助手”这样的App对接广告模式并进行源码搭建时,你需要遵循一系列步骤来确保广告的有效集成和App的稳定运行。以下是一个基本的流程指南:1.明确需求和广告模式需求分析:明确App需要对接的广告类型(如横幅广告、插屏广告、视频广告等)和广告展示策略。广告模式选择:根......