Preparation before use

  1. Android Studio Arctic Fox version or later

  2. For a new project, you can create a new Empty Compose Activity at the time of creation

  3. 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

  • RowRow 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
  • ColumnVertically arrayed view, its properties and aboveRowsimilar
  • BoxTo overlay one element on top of another, similar toFrameLayoutThis kind of

The view components

  • TextJust like a TextView in a native View
  • Buttonbutton
  • LazyColumnSimilar to native RecyclerView
  • ImagePicture control on the network picture, can be usedCoilThe framework
  • TextFieldFile entry box
  • SurfaceUsed to control component backgrounds, borders, text colors, etc
  • AlertDialogPopover 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 usTextViewOr 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…