Preparation before use
-
Android Studio Arctic Fox version or later
-
For a new project, you can create a new Empty Compose Activity at the time of creation
-
Add it to the build.gradle file of the Module
android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion compose_version kotlinCompilerVersion '1.4.32' } } dependencies { implementation 'androidx. Core: the core - KTX: 1.3.2' implementation 'androidx. Appcompat: appcompat: 1.2.0' implementation 'com. Google. Android. Material: material: 1.3.0' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling:$compose_version" implementation 'androidx. Lifecycle: lifecycle - runtime - KTX: 2.3.1' implementation 'androidx. Activity: activity - compose: 1.3.0 - alpha06' } Copy the code
You need to add
buildFeatures {
compose true
}
Copy the code
component
Component Definition
A UI component in Compose is a function annotated with @composable
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")}Copy the code
Layout of the components
If you write a single view directly to a Compose without a layout component, there will be an exception. Here’s what the official said:
A Composable function might emit several UI elements. However, if you don’t provide guidance on how they should be arranged, Compose might arrange the elements in a way you don’t like
Row
Row aligns views horizontally with the following attributes:inline fun Row( modifier: Modifier = Modifier, horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, verticalAlignment: Alignment.Vertical = Alignment.Top, content: @Composable RowScope. () - >Unit ) Copy the code
Column
Vertically arrayed view, its properties and aboveRow
similarBox
To overlay one element on top of another, similar toFrameLayout
This kind of
The view components
Text
Just like a TextView in a native ViewButton
buttonLazyColumn
Similar to native RecyclerViewImage
Picture control on the network picture, can be usedCoil
The frameworkTextField
File entry boxSurface
Used to control component backgrounds, borders, text colors, etcAlertDialog
Popover control, similar to the native ViewAlertDialog
Component state management
remember
Remember is used to record some related attribute values of components. When the attribute changes, it will automatically trigger the UPDATE of UI.
@Composable
fun HelloContent(a) {
Column(modifier = Modifier.padding(16.dp)) {
var nameState = remember { mutableStateOf("")}var name = nameState.value;
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
TextField(
value = name,
onValueChange = { println("data----->$it"); nameState.value = it } ) } }Copy the code
The function of this code is that when the user enters text in an input box, it will be displayed on the page immediately. When coded this way, the state is coupled to the component, which is fine when the caller doesn’t care about the internal state, but it has the disadvantage of making the component less reusable. In this case, we can use state promotion as a way to separate the state from the component
@Composable
fun HelloScreen(a) {
var nameState = remember { mutableStateOf("") }
HelloContent(name = nameState.value, onNameChange = { nameState.value = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) - >Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
TextField(
value = name,
onValueChange = { onNameChange(it) }
)
}
}
Copy the code
This is where you put the state outside of HelloContent, the aspect of the reuse of the HelloContent component
rememberSaveable
RememberSaveable When an activity or process is recreated (e.g. a screen rotation), its state information is not lost. Var nameState = remember {mutableStateOf(“”)} replace remember with rememberSaveable
ViewModel
You can use the ViewModel for global state management
class HelloViewModel : ViewModel() {
// LiveData holds state which is observed by the UI
// (state flows down from ViewModel)
private val _name = MutableLiveData("")
val name: LiveData<String> = _name
// onNameChange is an event we're defining that the UI can invoke
// (events flow up from UI)
fun onNameChange(newName: String) {
_name.value = newName
}
}
@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel()) {
// by default, viewModel() follows the Lifecycle as the Activity or Fragment
// that calls HelloScreen(). This lifecycle can be modified by callers of HelloScreen.
// name is the current value of [helloViewModel.name]
// with an initial value of ""
val name: String by helloViewModel.name.observeAsState("")
HelloContent(name = name, onNameChange = { helloViewModel.onNameChange(it) })
}
Copy the code
Modifers
Modifers are used to decorate the Composable, and Modifiers are used to tell a UI element how to layout, display, and associated behavior.
Layout related properties
fillMaxWidth
matchParentSize
height
width
padding
size
According to
background
clip
, such as:Modifier.clip(RoundedCornerShape(4.dp))
“And a rounded corner came out
The binding event
Clickable is used to bind events
Row(
Modifier
.fillMaxWidth()
.clickable { onClick(); },
verticalAlignment = Alignment.CenterVertically
) {
...
}
Copy the code
The instance
The development experience of using Compose solution is very similar to using Vue or React. The code structure is very clear and it saves a lot of work to draw UI without XML. Here is a code snippet to draw a wechat personal center page
@Preview(showBackground = true)
@Composable
fun PersonalCenter(a) {
Column() {
Header("Hello World"."Wechat_0001")
Divider(
Modifier
.fillMaxWidth()
.height(8.dp), GrayBg
)
RowList()
Divider(
Modifier
.fillMaxHeight(), GrayBg
)
}
}
@Composable
fun Header(nickName: String, wechatNo: String) {
Row(
Modifier
.fillMaxWidth()
.padding(24.dp, 24.dp, 16.dp, 24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(R.drawable.avatar),
contentDescription = "Avatar",
Modifier
.size(50.dp)
.clip(
RoundedCornerShape(4.dp)
)
)
Column() {
Text(nickName, Modifier.padding(12.dp, 2.dp, 0.dp, 0.dp), TextColor, fontSize = 18.sp)
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
"Wechat:$wechatNo",
Modifier
.padding(12.dp, 10.dp, 0.dp, 0.dp)
.weight(1.0 f), TextColorGray, fontSize = 14.sp
)
Icon(painterResource(R.drawable.ic_qrcode), "Two-dimensional code", Modifier.size(16.dp))
Icon(
painterResource(R.drawable.right_arrow_3),
contentDescription = "more",
Modifier.padding(12.dp, 0.dp, 0.dp, 0.dp)
)
}
}
}
}
@Composable
fun RowItem(@DrawableRes icon: Int, title: String, onClick: () -> Unit) {
Row(
Modifier
.fillMaxWidth()
.clickable { onClick(); },
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(icon), contentDescription = title + "icon",
Modifier
.padding(16.dp, 12.dp, 16.dp, 12.dp)
.size(24.dp)
)
Text(title, Modifier.weight(1f), TextColor, fontSize = 15.sp)
Icon(
painterResource(R.drawable.right_arrow_3),
contentDescription = "more",
Modifier.padding(0.dp, 0.dp, 16.dp, 0.dp)
)
}
}
@Composable
fun RowList(a) {
var context = LocalContext.current;
Column() {
RowItem(icon = R.drawable.ic_pay, title = "Pay") { onItemClick(context, "payment") }
Divider(
Modifier
.fillMaxWidth()
.height(8.dp), GrayBg
)
RowItem(icon = R.drawable.ic_collections, title = "Collection") {
onItemClick(context, "Collection")
}
Divider(
Modifier
.fillMaxWidth()
.padding(56.dp, 0.dp, 0.dp, 0.dp)
.height(0.2.dp), GrayBg
)
RowItem(icon = R.drawable.ic_photos, title = "Album") {
onItemClick(context, "Album")
}
Divider(
Modifier
.fillMaxWidth()
.padding(56.dp, 0.dp, 0.dp, 0.dp)
.height(0.2.dp), GrayBg
)
RowItem(icon = R.drawable.ic_cards, title = "Card package") {
Toast.makeText(context, "payment", Toast.LENGTH_SHORT).show()
}
Divider(
Modifier
.fillMaxWidth()
.padding(56.dp, 0.dp, 0.dp, 0.dp)
.height(0.2.dp), GrayBg
)
RowItem(icon = R.drawable.ic_stickers, title = "Expression") {
Toast.makeText(context, "payment", Toast.LENGTH_SHORT).show()
}
Divider(
Modifier
.fillMaxWidth()
.height(8.dp), GrayBg
)
RowItem(icon = R.drawable.ic_settings, title = "Settings") {
Toast.makeText(context, "payment", Toast.LENGTH_SHORT).show()
}
}
}
fun onItemClick(context: Context.data: String) {
Toast.makeText(context, data, Toast.LENGTH_SHORT).show()
}
Copy the code
The View of embedded Compose
var view = LinearLayout(this) view.addView(ComposeView(this).apply { setContent { PersonalCenter(); }})Copy the code
Compose the embedded View
@Compose
fun RowList(a){... AndroidView({View(context)}, Modifier.width(20.dp).height(20.dp).background(Color.Green)){}
...
}
Copy the code
conclusion
- Compose uses a new layout and rendering mechanism. The elements in Compose are different from the various views we have written in the past. For example, the Text in Compose is not familiar to us
TextView
Or other native controls, which use a lower level API to implement - Automatic subscription of data (complete bidirectional binding)
- Declarative UI: Compose uses an automatic subscription mechanism to automatically update the UI
- Compose mixes with the existing native View
reference
- Google Official Tutorials
- Developer.android.com/jetpack/com…
- Github.com/rengwuxian/…
- Developer.android.com/jetpack/com…
- En.wikipedia.org/wiki/Side_e…