如何在 Android 中使用 Jetpack Compose 创建计时器?
Jetpack Compose 是一个用于构建原生 Android UI 的现代工具包。 Jetpack Compose 以更少的代码、强大的工具和直观的 Kotlin API 简化并加速了 Android 上的 UI 开发。在本文中,我们将使用 Jetpack Compose 创建一个计时器。下面是示例视频,用于展示我们将要构建的内容。
分步实施
第 1 步:创建一个新项目
要使用 Jetpack Compose 在 Android Studio 中创建新项目,请参阅如何使用 Jetpack Compose 在 Android Studio Canary 版本中创建新项目。
第 2 步:使用 MainActivity.kt
转到MainActivity.kt文件并参考以下代码。下面是MainActivity.kt文件的代码。代码中添加了注释以更详细地理解代码。
Kotlin
import androidx.compose.ui.unit.dp
import androidx.activity.compose.setContent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PointMode
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(
color = Color(0xFF101010),
modifier = Modifier.fillMaxSize()
) {
Box(
contentAlignment = Alignment.Center
) {
// call the function Timer
// and pass the values
// it is defined below.
Timer(
totalTime = 100L * 1000L,
handleColor = Color.Green,
inactiveBarColor = Color.DarkGray,
activeBarColor = Color(0xFF37B900),
modifier = Modifier.size(200.dp)
)
}
}
}
}
}
// create a composable to
// Draw arc and handle
@Composable
fun Timer(
// total time of the timer
totalTime: Long,
// circular handle color
handleColor: Color,
// color of inactive bar / progress bar
inactiveBarColor: Color,
// color of active bar
activeBarColor: Color,
modifier: Modifier = Modifier,
// set initial value to 1
initialValue: Float = 1f,
strokeWidth: Dp = 5.dp
) {
// create variable for
// size of the composable
var size by remember {
mutableStateOf(IntSize.Zero)
}
// create variable for value
var value by remember {
mutableStateOf(initialValue)
}
// create variable for current time
var currentTime by remember {
mutableStateOf(totalTime)
}
// create variable for isTimerRunning
var isTimerRunning by remember {
mutableStateOf(false)
}
LaunchedEffect(key1 = currentTime, key2 = isTimerRunning) {
if(currentTime > 0 && isTimerRunning) {
delay(100L)
currentTime -= 100L
value = currentTime / totalTime.toFloat()
}
}
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.onSizeChanged {
size = it
}
) {
// draw the timer
Canvas(modifier = modifier) {
// draw the inactive arc with following parameters
drawArc(
color = inactiveBarColor, // assign the color
startAngle = -215f, // assign the start angle
sweepAngle = 250f, // arc angles
useCenter = false, // prevents our arc to connect at te ends
size = Size(size.width.toFloat(), size.height.toFloat()),
// to make ends of arc round
style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
)
// draw the active arc with following parameters
drawArc(
color = activeBarColor, // assign the color
startAngle = -215f, // assign the start angle
sweepAngle = 250f * value, // reduce the sweep angle
// with the current value
useCenter = false, // prevents our arc to connect at te ends
size = Size(size.width.toFloat(), size.height.toFloat()),
// to make ends of arc round
style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
)
// calculate the value from arc pointer position
val center = Offset(size.width / 2f, size.height / 2f)
val beta = (250f * value + 145f) * (PI / 180f).toFloat()
val r = size.width / 2f
val a = cos(beta) * r
val b = sin(beta) * r
// draw the circular pointer/ cap
drawPoints(
listOf(Offset(center.x + a, center.y + b)),
pointMode = PointMode.Points,
color = handleColor,
strokeWidth = (strokeWidth * 3f).toPx(),
cap = StrokeCap.Round // make the pointer round
)
}
// add value of the timer
Text(
text = (currentTime / 1000L).toString(),
fontSize = 44.sp,
fontWeight = FontWeight.Bold,
color = Color.White
)
// create button to start or stop the timer
Button(
onClick = {
if(currentTime <= 0L) {
currentTime = totalTime
isTimerRunning = true
} else {
isTimerRunning = !isTimerRunning
}
},
modifier = Modifier.align(Alignment.BottomCenter),
// change button color
colors = ButtonDefaults.buttonColors(
backgroundColor = if (!isTimerRunning || currentTime <= 0L) {
Color.Green
} else {
Color.Red
}
)
) {
Text(
// change the text of button based on values
text = if (isTimerRunning && currentTime >= 0L) "Stop"
else if (!isTimerRunning && currentTime >= 0L) "Start"
else "Restart"
)
}
}
}
输出:
想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!