前言 文本的输入框架本身提供了
BasicTextField
TextField
OutlinedTextField
BasicTextField是最基本的输入框,没有什么样式,也方便我们自定义,是我们最常用的组件。
后两者有自带的样式和交互效果,但是实际项目中并不符合我们的效果,所以一般很少用。
BasicTextField 基础示例 1 2 3 4 BasicTextField( value = "" , onValueChange = {}, )
文字样式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 BasicTextField( value = vm.jiexi.value, modifier = Modifier.fillMaxSize(), textStyle = TextStyle( color = Color(0xff333333 ), fontSize = 14. sp, lineHeight = 20. sp ), onValueChange = { value -> if (value.length > 100 ) { vm.jiexi.value = value.substring(0 , 100 ) } else { vm.jiexi.value = value } }, )
密码输入 1 2 3 4 5 6 7 8 BasicTextField( value = text, visualTransformation = if (inputVisible) { VisualTransformation.None } else { PasswordVisualTransformation() } )
其中
visualTransformation = VisualTransformation.None 显示输入字符
visualTransformation = PasswordVisualTransformation() 输入字符显示为密文形式
文本渐变和光标渐变 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Composable fun GradientTextField () { var text by remember { mutableStateOf("" ) } BasicTextField( value = text, onValueChange = { text = it }, textStyle = TextStyle( brush = Brush.linearGradient( colors = listOf(Color.Red, Color.Blue, Color.Green, Color.Magenta) ), fontSize = 32. sp ), cursorBrush = Brush.verticalGradient( colors = listOf(Color.Blue, Color.Cyan, Color.Red, Color.Magenta) ), ) }
placeholder 默认是不支持placeholder的,我们可以自定义实现。
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 import androidx.compose.foundation.focusableimport androidx.compose.foundation.layout.Boximport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.foundation.layout.paddingimport androidx.compose.foundation.text.BasicTextFieldimport androidx.compose.material3.Textimport androidx.compose.runtime.Composableimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.setValueimport androidx.compose.ui.Alignmentimport androidx.compose.ui.Modifierimport androidx.compose.ui.focus.onFocusChangedimport androidx.compose.ui.graphics.Colorimport androidx.compose.ui.graphics.SolidColorimport androidx.compose.ui.text.TextStyleimport androidx.compose.ui.unit.dpimport androidx.compose.ui.unit.sp@Composable fun BasicTextFieldWithPlaceholder ( fontSize: Int , placeholder: String , onFocusChange: (focus : Boolean ) -> Unit , onValueChange: (String ) -> Unit ) { var text by remember { mutableStateOf("" ) } BasicTextField( value = text, modifier = Modifier .fillMaxSize() .focusable() .onFocusChanged { focusState -> onFocusChange(focusState.isFocused) }, onValueChange = { text = it;onValueChange(it) }, singleLine = true , textStyle = TextStyle( color = Color(0xffeeeeee ), fontSize = fontSize.sp ), decorationBox = { innerTextField -> Box( modifier = Modifier .fillMaxSize() .padding(start = 8. dp, end = 8. dp) ) { if (text.isBlank()) { Text( modifier = Modifier .fillMaxWidth() .align(Alignment.Center), text = placeholder, style = TextStyle(color = Color.White), fontSize = fontSize.sp ) } Box( modifier = Modifier .fillMaxWidth() .align(Alignment.Center) ) { innerTextField() } } }, cursorBrush = SolidColor(Color.White), ) }
TextField 1 2 3 4 5 6 7 8 9 @Composable fun SimpleFilledTextFieldSample () { var text by remember { mutableStateOf("" ) } TextField( value = text, onValueChange = { text = it }, label = { Text("姓名" ) } ) }
输入类型为密码
1 2 3 4 5 6 7 8 9 10 11 12 @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) ) }
彩虹色文字
1 2 3 4 5 6 7 8 9 10 11 12 @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) ) }
OutlinedTextField 1 2 3 4 5 6 7 8 9 10 @Composable fun SimpleOutlinedTextFieldSample () { var text by remember { mutableStateOf("" ) } OutlinedTextField( value = text, onValueChange = { text = it }, label = { Text("Label" ) } ) }
去除涟漪效果 只要组件设置的可点击,就会出现涟漪效果,要想去除涟漪效果,我们可以扩展Modifier的方法来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import android.annotation .SuppressLintimport androidx.compose.foundation.clickableimport androidx.compose.foundation.interaction.MutableInteractionSourceimport androidx.compose.runtime.LaunchedEffectimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.setValueimport androidx.compose.ui.Modifierimport androidx.compose.ui.composedimport kotlinx.coroutines.delayinline fun Modifier.noRippleClickable (crossinline onClick: () -> Unit ) : Modifier = composed { clickable(indication = null , interactionSource = remember { MutableInteractionSource() }) { onClick() } }
使用方法:
把clickable更换为noRippleClickable即可。
两种组件封装形式 在对 BasicTextField 进行组件封装时,既可以使用 MutableState 也可以使用回调来在外层获取组件内的值。
下面分别介绍这两种方式的特点和使用场景。
使用 MutableState 原理 通过将 MutableState 对象作为参数传递给封装的 BasicTextField 组件,组件内部直接操作这个 MutableState 的值,由于 MutableState 是引用类型,所以在组件外部也能感知到其值的变化。
示例代码 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 import androidx.compose.foundation.text.BasicTextFieldimport androidx.compose.runtime.Composableimport androidx.compose.runtime.MutableStateimport androidx.compose.runtime.getValueimport androidx.compose.runtime.setValue@Composable fun CustomBasicTextField (textState: MutableState <String >) { var text by textState BasicTextField( value = text, onValueChange = { newText -> text = newText } ) } import androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.setValueimport androidx.compose.ui.window.singleWindowApplicationfun main () = singleWindowApplication { val textState = mutableStateOf("" ) CustomBasicTextField(textState) val currentText = textState.value println("当前文本值: $currentText " ) }
优缺点 优点
代码简洁 :使用 MutableState 可以减少回调函数的使用,使代码逻辑更加清晰。
数据流向明确 :直接操作状态对象,数据的流动方向一目了然,便于理解和维护。
缺点
耦合度较高 :组件与外部的状态紧密绑定,降低了组件的独立性和可复用性。
使用回调 原理 定义一个回调函数作为参数传递给封装的 BasicTextField 组件,当组件内部的值发生变化时,调用这个回调函数并将新的值作为参数传递出去。
示例代码 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 import androidx.compose.foundation.text.BasicTextFieldimport androidx.compose.runtime.Composableimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.setValue@Composable fun CustomBasicTextField (onTextChanged: (String ) -> Unit ) { var text by mutableStateOf("" ) BasicTextField( value = text, onValueChange = { newText -> text = newText onTextChanged(newText) } ) } import androidx.compose.ui.window.singleWindowApplicationfun main () = singleWindowApplication { var currentText by mutableStateOf("" ) CustomBasicTextField { newText -> currentText = newText println("当前文本值: $currentText " ) } }
优缺点 优点
解耦性强 :组件与外部的耦合度较低,组件只负责触发回调,不关心外部如何处理数据,提高了组件的可复用性。
灵活性高 :可以根据需要在回调函数中添加更多的逻辑,比如数据验证、格式化等。
缺点
代码复杂度增加 :需要定义和管理回调函数,增加了代码的复杂度。
选择建议
使用 MutableState 的场景 :当组件与外部的交互比较简单,且数据流向比较明确时,使用 MutableState 可以使代码更加简洁。
例如,组件只是简单地修改一个状态值,而不需要进行额外的逻辑处理。
使用回调的场景 :当组件需要与外部进行复杂的交互,或者需要在值变化时执行一些额外的逻辑时,使用回调可以提高组件的灵活性和可复用性。
例如,在值变化时需要进行数据验证、发送网络请求等操作。