前言
除了布局组件外,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
| Spacer(modifier = Modifier.height(16.dp))
|
分割线
这个写法已经废弃
1 2 3 4
| Divider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) )
|
新写法
横线
1 2 3 4
| HorizontalDivider( modifier = Modifier.height(1.dp), thickness = DividerDefaults.Thickness, color = Color.White )
|
渐变色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| HorizontalDivider( modifier = Modifier .height(0.5.dp) .background( Brush.horizontalGradient( listOf( Color.Red, Color.Blue, Color.Magenta, Color.Green, ) ) ), thickness = DividerDefaults.Thickness, color = Color.Transparent )
|
纯色
1 2 3 4 5 6
| HorizontalDivider( modifier = Modifier .height(0.5.dp) .background(Color.White), thickness = DividerDefaults.Thickness, color = Color.Transparent )
|
文本
Text(文本):
文本居中
1 2 3 4 5 6 7 8
| Text( text = "A", modifier = Modifier .background(Color.Red) .width(30.dp).height(30.dp) .wrapContentSize(Alignment.Center), textAlign = TextAlign.Center, )
|
设置行数
1 2 3 4 5 6 7 8 9
| Text( text = "ABC", modifier = Modifier .background(Color.Red) .width(30.dp).height(30.dp) .wrapContentSize(Alignment.Center), textAlign = TextAlign.Center, maxLines = 1 )
|
按钮
https://www.psvmc.cn/article/2024-03-13-jetpack-compose-button.html
文本输入
https://www.psvmc.cn/article/2024-03-13-jetpack-compose-textfield.html
图片
https://www.psvmc.cn/article/2024-03-13-jetpack-compose-image.html
加载中动画
1
| CircularProgressIndicator(modifier = Modifier.size(30.dp))
|
消息框
Toast
组件化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import android.annotation.SuppressLint import android.widget.Toast import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch
@SuppressLint("CoroutineCreationDuringComposition") @Composable fun ShowToast(message: String) { val context = LocalContext.current CoroutineScope(Dispatchers.Main).launch { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
|
调用
1 2 3 4 5
| var showToast by remember { mutableStateOf(false) }
if (showToast) { ShowToast("哈哈"); }
|
组件内方法
1 2 3 4 5 6 7 8
| val context = LocalContext.current
fun showToast(message: String) { CoroutineScope(Dispatchers.Main).launch { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
|
Snackbar
基本示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @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 = "关闭") } } ) } } }
|
使用snackbarHost
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
| 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 ) } } }
|
对话框
1 2 3 4 5 6 7 8 9
| Dialog(onDismissRequest = { }) { Surface( modifier = Modifier.size(300.dp), shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.background ) { Text("文字") } }
|
隐藏键盘
1 2 3 4 5 6
| val keyboardController = LocalSoftwareKeyboardController.current
fun hideKeyboard() { keyboardController?.hide() }
|
加载网页
1 2 3 4 5 6 7 8 9 10 11 12 13
| @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) } }) }
|
视频播放器
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
| 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 }) }
|
实战-登录页面
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
| @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 = "登录") } } }
|
调用
1 2 3
| LoginScreen { name, pwd -> Log.i("LoginScreen", "Username: $name, Password: $pwd") };
|
红点
1 2 3 4 5 6 7 8 9 10 11 12 13
| if (vm.needUpdate.value) { Surface( color = Color.Red, shape = CircleShape, modifier = Modifier .size(12.dp) .align(Alignment.TopEnd) .offset(x = 2.dp, y = -2.dp) ) { } }
|
组件提取
因为Compose组件本质都是方法,所以可以使用提取方法来提取组件
快捷键:Ctrl+Alt+M