Jetpack ComposeIt’s a new model for building native interfacesAndroidKit. It simplifies and speeds upAndroidUIDevelopment work. Use less code, powerful tools, and intuitiveKotlin API, fast buildAppUI.At presentJetpack ComposeAlphaVersion. So you need to be able toAndroid StudioCanaryOnly version can play.Download ANDROID STUDIO CANARY

1. CreateJetpack Composeproject

The Compose template is already available in the Android Studio Canary version, so select the Empty Compose Activity template when creating your project.

At this point, you are done creating a Compose project. In addition, we can also choose to import the Jetpack Compose Sample application, following the steps of the Jetpack Compose Sample.

2. Compose function usage

Compose is a function-based declarative UI builder. For example, display a text in mainActivity.kt.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello Compose!")}}}Copy the code

This is a big difference from using XML layout. The setContent block defines the layout of the Activity. Instead of using an XML file to define the layout content, we call a Compose function, such as the Text function above. Jetpack Compose then uses a custom Kotlin compiler plug-in to convert these Compose functions into interface elements for the application.

2.1 Composefunction

Jetpack Compose is built around the Compose function and can be developed to describe the style layout and data dependencies of the application interface rather than the process of building the interface. Adding the @composable annotation to a function creates the Compose function. Note that the Compose function can only be called within the bounds of the other Compose functions. Let’s move the Text from the above example into the custom Compose function.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { HelloCompose() } } @Composable fun HelloCompose() { Text("Hello Compose!" )}}Copy the code
2.3 Setting tap Listening

In addition to using the Text function, there are other basic functions we can use, such as Button, Image, and so on. So how do you set click-listening for UI controls? There are two ways to do this in the Compose framework:

  • For similarButtonThis type of function providesonClickFunctional interface for external Settings click listening;
  • For similarTextFunction, which does not provide explicit interface Settings, passesModifierClass Settings click listen;

ButtonThe function sets the click event

@Composable
fun TextButton(a) {
    Button(
        onClick = {
            Log.d("Andoter".this.javaClass.name)
            Toast.makeText(this@MainActivity."Click the Button", Toast.LENGTH_SHORT).show()
        }
    ) {
        Text(text = "Hello Compose!", color = Color.Red)
    }
}
Copy the code

The onClick function can be set to achieve the click implementation. Note that the Button function does not set the Text content, so it needs to set the Text content through the Text function.

TextThe function sets the click event

@Composable
fun ClickedText(a) {
    val modifier = Modifier.clickable(onClick = {
        Log.d("Andoter".this.javaClass.name)
        Toast.makeText(this@MainActivity."Click the Button", Toast.LENGTH_SHORT).show()
    })

    Text(text = "Hello Compose!",modifier = modifier.padding(10.dp))
}
Copy the code

Set click events through Modifier. Clickable. Modifier allows you to set not only click events but also control layout properties.

  • clickable(): Set tap listening
  • padding(): Leave space around elements
  • fillMaxWidth(): causes the composable item to fill the maximum width given to it by its parent
  • preferredSize(): Specifies the preferred width and height of the element
2.4 preview

inComposeFramework forComposeFunction provides preview capability by givingComposeThe function to add@PreviewComments can be previewed. In real development, preview functions should not be posted online, so it is best to create separate preview functions that will not be called by the application to see the effect in action. Dedicated preview functions can improve performance and make it easier to set up multiple previews later.

3. The layout

In Jetpack Compose, all elements are grouped around the Compose function, so the layout is implemented using the corresponding built-in Compose function.

3.1 ColumnRow

Characteristics of both:

  • Column: to arrange the elements in a vertical direction;
  • Row: To arrange elements in a horizontal direction;
  • Stack: Puts an element on top of another element.

Here we use the Column function as an example.

@Preview
@Composable
fun MultiText(a) {
    Text(text = "Hello Compose!")
    Text("Ant learning Compose!")}@Preview
@Composable
fun ColumnText(a) {
    Column {
        Text(text = "Hello Compose!")
        Text("Ant learning Compose!")}}Copy the code

Column can be used to arrange components in the vertical direction to preview effect comparison:

3.2 ScrollableRowScrollableColumn

Use ScrollableRow or ScrollableColumn to scroll elements in a Row or Column.

@Composable
fun ProductList(a) {
    ScrollableColumn(Modifier.fillMaxSize()) {
        listOf("Ant"."Andoter"."Little white").forEach { value ->
            ProductDetailView(value)
        }
    }
}

@Composable
fun ProductDetailView(text: String) {
    val image = imageResource(id = R.drawable.header)
    Column(modifier = Modifier.padding(16.dp)) {
        val imageModifier = Modifier
            .preferredHeight(180.dp)
            .clip(shape = RoundedCornerShape(5.dp))
            .fillMaxWidth()
            .clickable(onClick = {
                Log.d("Ant"."click");
            })
        Image(image, modifier = imageModifier, contentScale = ContentScale.Crop)
        Spacer(modifier = Modifier.preferredHeight(16.dp))
        Text("Hello Compose!")}}Copy the code

4. ComposeThe interface structure

Now that you have a basic idea of Compose, how does the Compose function draw on the screen? In what form? We use the Layout Inspector tool to view a Compose page.

In the Compose framework, TextView, Button, ImageView, etc., are now obsolete. Instead, it is implemented using AndroidComposeView (inheriting ViewGroup), ViewLayerContainer (inheriting ViewGroup), and ViewLayer (inheriting View) controls, Where ViewLayer represents each View control View.

To viewViewLayerCan get the generating relation of view:LayerWrapperAndroidComposeView -> ViewLayer.

5. ComposeImpact on services

Jetpack Compose is a new declarative interface tool kit for Android, and the setting mode of click monitor has also changed greatly. Therefore, for me, the most intuitive business impact is that the original interpolation technology can no longer be used to collect click events. This area needs to be investigated and adapted.

The above mentioned two ways to set the click, are essentially through the Modifier to achieve, look at the following example.

@Composable
fun ClickedText(a) {
    val modifier = Modifier.clickable(onClick = {
        Log.d("Andoter".this.javaClass.name)
        Toast.makeText(this@MainActivity."Click the Button", Toast.LENGTH_SHORT).show()
    })

    Text(text = "Hello Compose!", modifier = modifier.padding(10.dp))
}
Copy the code

Use the Modifier to set click monitor for a Text that pops up a Toast when clicked. Decompile to see the final implementation.

/* access modifiers changed from: package-private */
@Metadata(mo23161bv = {1, 0, 3}, mo23164k = 3, mo23165mv = {1, 4, 0})
/* compiled from: MainActivity.kt */
public final class MainActivity$TextButton$1 $1extends Lambda implements Function0<Unit> {
    private final /* synthetic */ MainActivity $this;

    /* JADX INFO: super call moved to the top of the method (can break code semantics) */
    MainActivity$TextButton$1$1(MainActivity mainActivity) {
        super(0);
        this. $this = mainActivity;
    }

    @Override // kotlin.jvm.functions.Function0
    public final void invoke() {
        Log.d(LiveLiterals$MainActivityKt.INSTANCE.mo17059x27db7fde(), this. $this.getClass().getName());
        Toast.makeText(this. $this, LiveLiterals$MainActivityKt.INSTANCE.mo17064x88044b3e(), 0).show(); }}Copy the code

Kotlin is eventually converted to a class that inherits Lambda and implements the Fuction0 interface to host implementation click-listening. In this way, we can summarize Hook conditions:

  • kotlin.jvm.internal.LambdaA subclass of
  • implementationkotlin.jvm.functions.Functioninterface
  • bepublicfinalThe modifierinvokemethods

Although the Hook point has been found, it is still unable to break through and obtain the corresponding View, and the properties read by the View cannot be obtained. I hope we can discuss it together.

6. Summary

The Android view hierarchy has long been represented as a tree of interface widgets. The interface is updated by iterating the tree with functions like findViewById(), which increases the likelihood of errors by manipulating the view manually. In the past few years, mobile devices have been moving towards declarative interface models, such as Flutter and Swift UI, so the Jetpack Compose framework should be a next step.

For more information

  • Android Jetpack Compose