除了布局组件外,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
Spacer(modifier = Modifier.height(16.dp))
Divider(
color = Color.Black,
modifier = Modifier.fillMaxHeight().width(1.dp)
)
Text(文本):
Text("Hello, World!")
文本居中
Text(
text = "A",
modifier = Modifier
.background(Color.Red)
.width(30.dp).height(30.dp)
.wrapContentSize(Alignment.Center),
textAlign = TextAlign.Center,
)
设置行数
Text(
text = "ABC",
modifier = Modifier
.background(Color.Red)
.width(30.dp).height(30.dp)
.wrapContentSize(Alignment.Center),
textAlign = TextAlign.Center,
maxLines = 1
)
Button(
modifier = Modifier.width(100.dp).height(40.dp),
shape = MaterialTheme.shapes.medium,
onClick = { /* 按钮点击事件 */ }
) {
Text(
text = "点击",
fontSize = 16.sp,
color = Color.White
)
}
效果
组件定义
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),
)
}
}
使用
Box(
modifier = Modifier
.align(Alignment.Bottom)
.size(72.dp, 28.dp)
.clip(RoundedCornerShape(6.dp))
.clickable { }) {
ZBtnView("安装")
}
@Composable
fun MyRadioBtn(onSelectChange: (Boolean) -> Unit) {
val isSelected = remember {mutableStateOf(false)}
RadioButton(selected = isSelected.value, onClick = {
isSelected.value = !isSelected.value
onSelectChange(isSelected.value)
})
}
@Composable
fun SwitchMinimalExample() {
var checked by remember { mutableStateOf(true) }
Switch(
checked = checked,
onCheckedChange = {
checked = it
}
)
}
BasicTextField(
value = "",
onValueChange = {},
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SimpleFilledTextFieldSample() {
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("姓名") }
)
}
输入类型为密码
@Composable
fun PasswordTextField() {
var password by rememberSaveable { mutableStateOf("") }
TextField(
value = password,
onValueChange = { password = it },
label = { Text("Enter password") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
彩虹色文字
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SimpleFilledTextFieldSample() {
var text by remember { mutableStateOf("") }
val brush = remember {
Brush.linearGradient(
colors = listOf<Color>(Color.Red, Color.Green, Color.Blue)
)
}
TextField(
value = text, onValueChange = { text = it }, textStyle = TextStyle(brush = brush)
)
}
@Composable
fun SimpleOutlinedTextFieldSample() {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") }
)
}
Image(
modifier = Modifier
.padding(10.dp)
.size(200.dp, 150.dp)
.background(color = Color.Yellow),
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
contentScale = ContentScale.Crop
)
contentScale:
ContentScale.Fit
等比缩放 保证图片完全显示 默认的方式ContentScale.Crop
等比缩放后居中剪裁ContentScale.Inside
等比缩放保证图片完全显示ContentScale.FillBounds
拉伸填充ContentScale.FillHeight
等比缩放 填充高度ContentScale.FillWidth
等比缩放 填充宽度ContentScale.None
不缩放后居中剪裁非透明的PNG图片的区域添加着色。
Image(
modifier = Modifier
.padding(10.dp)
.size(200.dp, 150.dp),
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
colorFilter = ColorFilter.tint(color = Color.Green, BlendMode.SrcAtop)
)
Image(
modifier = Modifier
.padding(10.dp)
.size(200.dp)
.background(color = Color.Yellow)
.clip(shape = CircleShape),
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
contentScale = ContentScale.Crop,
)
Image(
modifier = Modifier
.padding(10.dp)
.size(200.dp)
.background(color = Color.Yellow)
.clip(shape = RoundedCornerShape(20.dp)),
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
contentScale = ContentScale.Crop,
)
图片的背景是不会被剪裁的,我们可以在外面套一个Box做剪裁。
Box(
modifier = Modifier
.padding(10.dp)
.size(200.dp)
.clip(shape = RoundedCornerShape(20.dp)),
) {
Image(
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
modifier = Modifier
.background(color = Color.Yellow)
.fillMaxSize(),
contentScale = ContentScale.Crop
)
}
Image(
painter = painterResource(R.drawable.my_image),
contentDescription = "My Image"
)
Image(
painter = painterResource(id = R.drawable.logo),
modifier = Modifier
.padding(10.dp)
.size(46.dp)
.drawWithContent {
drawContent()
drawCircle(
Color.Red,
5.dp.toPx(),
Offset(size.width - 1.dp.toPx(), 1.dp.toPx())
)
},
contentDescription = "头像"
)
添加依赖
implementation("io.coil-kt:coil-compose:2.6.0")
添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
使用
@Composable
fun LoadWebImage(url:String){
AsyncImage(
model = url,
contentDescription = null,
)
}
调用
LoadWebImage(url = "https://www.psvmc.cn/head.jpg")
设置占位图
@Composable
fun LoadWebImage(url:String){
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.crossfade(true)
.build(),
placeholder = painterResource(R.drawable.ic_launcher_foreground),
contentDescription = stringResource(R.string.app_name),
contentScale = ContentScale.Crop,
modifier = Modifier.clip(CircleShape).size(60.dp)
)
}
CircularProgressIndicator(modifier = Modifier.size(30.dp))
import android.widget.Toast
import androidx.compose.runtime.Composable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun ShowToast(message: String) {
val context = LocalContext.current
// 启动一个协程来显示 Toast
CoroutineScope(Dispatchers.Main).launch {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
调用
var showToast by remember { mutableStateOf(false) }
if (showToast) {
ShowToast("哈哈");
}
val context = LocalContext.current
// 显示 Toast 的函数
fun showToast(message: String) {
CoroutineScope(Dispatchers.Main).launch {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
@Composable
fun SnackbarExample() {
var snackbarVisible by remember { mutableStateOf(false) }
Box {
Button(onClick = { snackbarVisible = true }) {
Text("显示 Snackbar")
}
if (snackbarVisible) {
Snackbar(
content = { Text(text = "文本") },
action = {
Button(onClick = { snackbarVisible = false }) {
Text(text = "关闭")
}
}
)
}
}
}
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
},
floatingActionButton = {
}
) { contentPadding ->
Box {
Button(
modifier = Modifier.padding(10.dp).width(100.dp).height(40.dp),
shape = MaterialTheme.shapes.medium,
onClick = {
scope.launch {
snackbarHostState.showSnackbar("我是提示消息")
}
}
){
Text(
text = "点击",
fontSize = 16.sp,
color = Color.White
)
}
}
}
Dialog(onDismissRequest = { /* 关闭对话框事件 */ }) {
Surface(
modifier = Modifier.size(300.dp),
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colorScheme.background
) {
Text("文字")
}
}
val keyboardController = LocalSoftwareKeyboardController.current
// 在需要隐藏键盘的地方调用这个函数
fun hideKeyboard() {
keyboardController?.hide()
}
@Composable
fun WebViewContainer(url: String) {
AndroidView(factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
loadUrl(url)
}
})
}
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
@Composable
fun VideoPlayer(videoUrl: String) {
val context = LocalContext.current
val exoPlayer = SimpleExoPlayer.Builder(context).build().apply {
val dataSourceFactory = DefaultDataSourceFactory(
context,
Util.getUserAgent(context, context.getString(R.string.app_name))
)
val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(videoUrl))
prepare(videoSource)
}
AndroidView(factory = { ctx ->
PlayerView(ctx).apply {
player = exoPlayer
useController = true
}
}, update = { playerView ->
playerView.player = exoPlayer
})
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(onLoginClicked: (String, String) -> Unit) {
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
Log.i("LoginScreen", "Username: $username, Password: $password")
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("用户名") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
Log.i("登录点击", "Username: $username, Password: $password")
onLoginClicked(username, password)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "登录")
}
}
}
调用
LoginScreen { name, pwd ->
Log.i("LoginScreen", "Username: $name, Password: $pwd")
};
因为Compose组件本质都是方法,所以可以使用提取方法来提取组件
快捷键:Ctrl+Alt+M