Jetpack Compose中的基本组件-按钮(Button)、单选(RadioButton)、Switch

前言

除了布局组件外,Jetpack Compose 还提供了一系列其他常用的 UI 组件。

组件

https://developer.android.google.cn/jetpack/compose/components?hl=zh-cn

入门教程

https://developer.android.google.cn/courses/pathways/compose?hl=zh-cn

按钮

基本使用

1
2
3
4
5
6
7
8
9
10
11
Button(
modifier = Modifier.width(100.dp).height(40.dp),
shape = MaterialTheme.shapes.medium,
onClick = { /* 按钮点击事件 */ }
) {
Text(
text = "点击",
fontSize = 16.sp,
color = Color.White
)
}

默认的按钮是圆角的,所以这里不使用Button来改自定义效果。

颜色渐变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun LoginBtn(text: String, clickEvent: () -> Unit) {
val mShape = RoundedCornerShape(10.dp)
Box(
modifier = Modifier

.fillMaxSize()

.background(
brush = Brush.horizontalGradient(
colors = listOf(
Color(0xff24adfa),
Color(0x0ac2ff05),
), // 定义垂直渐变色
startX = 0f,
),
shape = mShape
)

.border(
width = 0.5.dp,
brush = Brush.linearGradient(
colors = listOf(Color(0xffADC9D9), Color(0xffADC9D9)),
start = androidx.compose.ui.geometry.Offset(0f, 0f),
end = androidx.compose.ui.geometry.Offset(100f, 100f)
),
shape = mShape
)
.clip(mShape)
.clickable {
clickEvent()
}
) {
Text(
text = text,
color = Color.White,
style = TextStyle(fontSize = 24.sp),
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.Center)
.wrapContentSize(Alignment.Center),
)
}
}

背景色

  1. 推荐使用 ButtonDefaults.buttonColors:它会自动处理按钮的各种状态(按压、禁用等),且符合 Material Design 设计规范。
  2. containerColor 参数:在 Material3 中,containerColor 用于设置按钮的背景色(替代了 Material2 中的 backgroundColor)。
  3. 自定义背景时:需将 containerColor 设为 Color.Transparent 以清除默认背景,避免样式冲突。
  4. 形状一致性:自定义背景时建议使用 ButtonDefaults.shape 保持默认圆角,或通过 shape 参数指定自定义形状。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Button(
modifier = Modifier
.padding(top = 40.dp)
.fillMaxWidth()
.height(55.dp)
.clip(CommonTheme.CornerFull),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0x55ffffff), // 默认状态
),
onClick = {
val intent = Intent(baseContext, MainActivity::class.java)
intent.putExtra("name", "张三")
startActivity(intent)
}) {
Text("立即登录", fontSize = 24.sp, color = Color(0xff253A70))
}

注意

通过background设置是不生效的。

自定义按钮

效果

image-20240321233209257

组件定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun ZBtnView(text:String){
val mShape = RoundedCornerShape(6.dp)
Box(
modifier = Modifier
.fillMaxSize()
.clip(mShape)
) {
Box(
modifier = Modifier
.padding(0.dp,6.dp,0.dp,0.dp)
.fillMaxSize()
.background(
Color(0xff2B89E0),
shape =mShape
)
.clip(mShape)
)
Box(
modifier = Modifier
.padding(0.dp,0.dp,0.dp,2.5.dp)
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color(0xff8AEFFD),
Color(0xff3BD9FD),
Color(0xff32C8FD),
Color(0xff36B3FE),
Color(0xff50B8FF),
), // 定义垂直渐变色
startY = 0f,
),
shape = mShape
)
.clip(mShape)
)
Text(
text = text,
color = Color.White,
style = TextStyle(fontSize = 14.sp),
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.Center)
.wrapContentSize(Alignment.Center),
)
}
}

使用

1
2
3
4
5
6
7
8
Box(
modifier = Modifier
.align(Alignment.Bottom)
.size(72.dp, 28.dp)
.clip(RoundedCornerShape(6.dp))
.clickable { }) {
ZBtnView("安装")
}

点击去涟漪/防止连点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import android.annotation.SuppressLint
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import kotlinx.coroutines.delay

@SuppressLint("ModifierFactoryUnreferencedReceiver")
inline fun Modifier.noRippleClickable(crossinline onClick: () -> Unit): Modifier = composed {
clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }) {
onClick()
}
}

@SuppressLint("ModifierFactoryUnreferencedReceiver")
fun Modifier.debouncedClickable(delay: Long = 500, onClick: () -> Unit) = composed {
//按钮是否可点击
var canClick by remember {
mutableStateOf(true)
}
LaunchedEffect(key1 = canClick, block = {
if (!canClick) {
delay(delay)
canClick = true
}
})

Modifier.clickable(canClick) {
canClick = false
onClick()
}
}

单选按钮

1
2
3
4
5
6
7
8
@Composable
fun MyRadioBtn(onSelectChange: (Boolean) -> Unit) {
val isSelected = remember {mutableStateOf(false)}
RadioButton(selected = isSelected.value, onClick = {
isSelected.value = !isSelected.value
onSelectChange(isSelected.value)
})
}

单选自定义

效果

image-20250821104843571

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp


@Composable
fun RadioGroup(
items: List<String>,
selectIndex: MutableState<Int> = mutableStateOf(0),
onSelect: (Int) -> Unit = {}
) {
Row(
modifier = Modifier
.height(26.dp)
.wrapContentWidth()
.clip(RoundedCornerShape(4.dp))
.background(Color.White, RoundedCornerShape(4.dp))
.border(0.5.dp, Color(0xff0085F7), RoundedCornerShape(4.dp))
) {
items.forEachIndexed { index, item ->
Box(
modifier = Modifier
.fillMaxHeight()
.wrapContentWidth()
.background(if (index == selectIndex.value) Color(0xff0085F7) else Color.Transparent)
.clickable {
selectIndex.value = index
onSelect(index)
}
.padding(start = 8.dp, end = 8.dp),
contentAlignment = Alignment.Center
)
{
Text(
text = item,
color = if (index == selectIndex.value) Color.White else Color(0xff75767A),
textAlign = TextAlign.Center,
fontSize = 14.sp
)
}
}
}
}

@Preview
@Composable
fun RadioGroupPreview() {
Box(Modifier.padding(10.dp)){
RadioGroup(
items = listOf("图形", "表格"),
)
}

}

Switch

1
2
3
4
5
6
7
8
9
10
@Composable
fun SwitchMinimalExample() {
var checked by remember { mutableStateOf(true) }
Switch(
checked = checked,
onCheckedChange = {
checked = it
}
)
}