scss
class TextFieldActivity : AppCompatActivity() {
@InternalTextApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This is an extension function of Activity that sets the @Composable function that's
// passed to it as the root view of the activity. This is meant to replace the .xml file
// that we would typically set using the setContent(R.id.xml_file) method. The setContent
// block defines the activity's layout.
setContent {
// We create a ScrollState that's "remember"ed to add proper support for a scrollable component.
// This allows us to also control the scroll position and other scroll related properties.
// remember calculates the value passed to it only during the first composition. It then
// returns the same value for every subsequent composition. More details are available in the
// comments below.
val scrollState = rememberScrollState()
// Column is a composable that places its children in a vertical sequence. You
// can think of it similar to a LinearLayout with the vertical orientation.
Column(
modifier = Modifier.verticalScroll(scrollState)
) {
// Title Component is a custom composable that we created which is capable of
// rendering text on the screen in a certain font style & text size.
TitleComponent("This is a Simple Text Input field")
SimpleTextInputComponent()
TitleComponent("This is a TextInput with custom text style")
CustomStyleTextInputComponent()
TitleComponent("This is a TextInput suitable for typing numbers")
NumberTextInputComponent()
TitleComponent("This is a search view created using TextInput")
SearchImeActionInputComponent()
TitleComponent("This is a TextInput that uses a Password Visual Transformation")
PasswordVisualTransformationInputComponent()
TitleComponent("This is a filled TextInput field based on Material Design")
MaterialTextInputComponent()
}
}
}
}
使用Column布局,类似于XML的LinearLayout。
然后,这里面使用到可滚动状态对象scrollState:
这是 Jetpack Compose 里可滚动状态对象的用法。
val scrollState = rememberScrollState()
创建并记住 一个ScrollState
。它保存当前滚动位置(像素),并在重组时复用同一个实例;否则每次重组都会重置滚动位置。
你也可以指定初始值:rememberScrollState(initial = 0)
。Modifier.verticalScroll(scrollState)
把这个状态应用到Column
上,使 Column 的内容超过屏幕时可以竖向滚动 。scrollState
用来读写滚动位置、做动画滚动等。
============================================================
Tex组件的使用,修饰:
修饰,使用TextStyle;Text整体的宽,高,padding,通过modifier修饰。
kotlin
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun TitleComponent(title: String) {
// Text is a predefined composable that does exactly what you'd expect it to - display text on
// the screen. It allows you to customize its appearance using style, fontWeight, fontSize, etc.
Text(
title, style = TextStyle(
fontFamily = FontFamily.Monospace, fontWeight = FontWeight.W900,
fontSize = 14.sp, color = Color.Black
), modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
)
}
=====================================================
rember,multableStateof,by
对状态变化做出响应。
在 Compose 中,对状态变化作出响应 是核心行为。你会注意到几个与 Compose 相关的新关键字------remember 和 mutableStateOf 。remember {}
是一个辅助的可组合函数,它只在第一次组合(composition)时计算传入的值,随后每次重组都会返回同一个值,具体含义是,返回同一个实例,避免状态被重置 。接着,可以把 mutableStateOf
看作一个可观察的值 :这个实例会被记住,因为使用了rember定义,但是实例的内容会变化,当这个变量更新时,所有访问它的可组合函数都会被重新组合(recompose) 。我们完全不需要显式订阅;任何读取该值的可组合项,在值发生变化时都会被重新组合。这样就能保证只有依赖该值的可组合项会重绘 ,其余部分(其它没有依赖该值的组合项,不会重绘)保持不变,从而实现高效 并作为一种性能优化 。这种理念受到了像 React 等现有框架的启发。
csharp
var textValue by remember { mutableStateOf(TextFieldValue("Enter your text here")) }
-
mutableStateOf(...)
:创建一个可观察的状态对象MutableState<TextFieldValue>
,内部初始值是TextFieldValue("Enter your text here")
。当它的value
改变时,读取它的可组合项会触发重组。 -
remember { ... }
:把上面的状态对象记住在组合树中,只在第一次组合时创建;后续重组复用同一个实例,避免状态被重置。 -
var textValue by ...
:Kotlin 的属性委托 语法(by
)。它把MutableState<TextFieldValue>
的value
属性解包成普通变量 来用:读textValue
等于读state.value
,写textValue = ...
等于写state.value = ...
。这样写更简洁。
在 BasicTextField
中如何工作
ini
BasicTextField(
value = textValue,
onValueChange = { textValue = it },
...
)
- 这是一个受控输入 (controlled component):
value
由你传入的textValue
决定。 - 用户输入 → 触发
onValueChange(it)
→ 你把textValue
更新为it
→ 状态变化引发重组 → 以新值再次渲染BasicTextField
。
less
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@InternalTextApi
@Composable
fun SimpleTextInputComponent() {
// Surface is a composable provided to fulfill the needs of the "Surface" metaphor from the
// Material Design specification. It's generally used to change the background color, add
// elevation, clip or add background shape to its children composables.
// You can think of Modifiers as implementations of the decorators pattern that are used to
// modify the composable that its applied to. In this example, we assign a padding of
// 16dp to the Surface.
Surface(color = Color.LightGray, modifier = Modifier.padding(16.dp)) {
// BasicTextField is a composable that is capable of accepting text user input. It renders the
// value that you pass to the "value" field. In order to update this as the user is
// typing a new string, we make use of the state delegate.
// Reacting to state changes is the core behavior of Compose. You will notice a couple new
// keywords that are compose related - remember & mutableStateOf.remember{} is a helper
// composable that calculates the value passed to it only during the first composition. It then
// returns the same value for every subsequent composition. Next, you can think of
// mutableStateOf as an observable value where updates to this variable will redraw all
// the composable functions that access it. We don't need to explicitly subscribe at all. Any
// composable that reads its value will be recomposed any time the value
// changes. This ensures that only the composables that depend on this will be redraw while the
// rest remain unchanged. This ensures efficiency and is a performance optimization. It
// is inspired from existing frameworks like React.
var textValue by remember { mutableStateOf(TextFieldValue("Enter your text here")) }
BasicTextField(
value = textValue,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
// Update value of textValue with the latest value of the text field
onValueChange = {
textValue = it
}
)
}
}
================================================
修饰输入框的样式
TextStyle
ini
var textValue by remember { mutableStateOf(TextFieldValue("Enter your text here")) }
BasicTextField(
value = textValue,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
// You can also customize the appearance of the TextInput by passing a TextStyle
// configuration to the TextField composable. If you don't pass this, it's just going
// to use the default values for all the properties.
textStyle = TextStyle(
color = Color.Blue,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
),
// Update value of textValue with the latest value of the text field
onValueChange = {
textValue = it
}
)
==================================================
限制输入框的输入内容,限定为输入数字,邮箱,密码之类。
使用keyboardOptions属性限定。
scss
var textValue by remember { mutableStateOf(TextFieldValue("123")) }
BasicTextField(
value = textValue,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
// Setting the keyboard type allows you to configure what kind of data you can input
// in this TextInput. Some examples are number, phone, email, password, etc.
// Update value of textValue with the latest value of the text field
onValueChange = {
textValue = it
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
)
)