Compose profile
- Jetpack Compose: Toolkit for building native Android interfaces (UIs) using declarative programming
advantage
- Much less code, much less code
- Powerful tool/component support
- Intuitive Kotlin API
- Simple and easy to use
Compose programming idea
-
Declarative programming paradigm: Declarative functions build a simple interface component without modifying any XML layout or using a layout editor. Simply call the Jetpack Compose function to declare the desired elements, and the Compose compiler does all the rest
-
For example: simple composable functions
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?). { super.onCreate(savedInstanceState) setContent { Text("Hello world!")}}}Copy the code
-
Dynamic: The composite function is written in Kotlin instead of XML, as shown above in the passage of $name
-
Matters needing attention:
-
Composable functions can be executed in any order
// You can do this in any order, you can't have StartScreen() set a global variable (side effect) and have MiddleScreen() take advantage of the change. Instead, each of these functions needs to remain independent. @Composable fun ButtonRow(a) { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } } Copy the code
-
Composable functions can be executed in parallel
-
Compose can optimize recombination by running composable functions in parallel, so that Compose can leverage multiple cores and run composable functions with lower priority (not on screen)
-
This optimization means that composable functions might be executed in a background thread pool, and if a composable function calls a function on the ViewModel, Compose might call that function from multiple threads at the same time
-
When a composable function is called, the call may occur on a different thread from the caller, which means that code that modifiable variables in a composable lambda should be avoided, both because such code is not thread-safe code and because it is a side effect of a composable lambda that is not allowed
// This code has no side effects @Composable fun ListComposable(myList: List<String>) { Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") } } Text("Count: ${myList.size}")}}Copy the code
// If the function writes local variables, this is not thread-safe or correct code: @Composable @Deprecated("Example with bug") fun ListWithBug(myList: List<String>) { var items = 0 Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") items++ // Avoid! Side-effect of the column recomposing. } } Text("Count: $items")}}// Each reorganization changes items. This can be every frame of the animation, or when the list is updated. Either way, the interface displays the wrong number of items. Therefore, Compose does not support such writes; By disallowing such writes, we allow the framework to change threads to perform composable lambdas. Copy the code
-
-
Recombination skips as many composable functions and lambdas as possible
-
Restructuring is an optimistic move and may be cancelled
-
Composable functions may run as frequently as each frame of an animation
-
Environment to prepare
-
If you already know, you can skip it
-
Upgrade to Arctic Fox 2020-3-1 and above. Android Studio does not support this version.
-
We note that this project only supports Kotlin with a minimum SDK version of 21, Android 5.0
-
Gradle Compose related dependencies
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx. Lifecycle: lifecycle - runtime - KTX: 2.3.1'
implementation 'androidx. Activity: activity - compose: 1.3.0 - alpha06'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx. Test. Ext: junit: 1.1.3'
androidTestImplementation 'androidx. Test. Espresso: espresso - core: 3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
Copy the code
kotlinOptions {
jvmTarget = '1.8'
useIR = true// Specify additional compiler options in the Gradle build script to enable the new JVM IR back end
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion '1.5.10'
}
buildFeatures {
compose true
}
packagingOptions {
resources {
excludes += '/ meta-inf / {AL2.0, LGPL2.1}'}}Copy the code
- Since the new release invites Java 11, installing the Java 8 environment requires the following fixes
Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
You can try some of the following options:
- changing the IDE settings.
- changing the JAVA_HOME environment variable.
- changing `org.gradle.java.home` in `gradle.properties`.
Copy the code
org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk11.011..jdk/Contents/Home
Copy the code
- @preview working, environment fine
layout
-
Android traditionally changes from XML-state, programmers need a lot of code to maintain the Ui interface to achieve the correctness of the interface state, time-consuming and laborious, even with the help of MVVM architecture, also need to maintain the state, because there is only one set of layout
-
Different from traditional XML implementations, the Compose declarative layout directly recreates the UI, so there are no state issues
-
Text: Compose provides the basic BasicText and BasicTextField, which are the main functions for displaying Text and processing user input. Compose also provides more advanced Text and Textfields
Text("Hello World") Copy the code
-
Restructuring the Text – > Button
@Composable fun ClickCounter(clicks: Int, onClick: () -> Unit) { Button(onClick = onClick) { Text("I've been clicked $clicks times")}}Copy the code
-
Modifier can modify control position, height, margin, alignment, and so on
// 'padding' sets the padding of each UI. There are four ways to overload a padding. Modifier.padding(10.dp) // Set the top, bottom, left and right to the same value Modifier.padding(10.dp, 11.dp, 12.dp, 13.dp) // Set the upper, lower, left, and right values respectively Modifier.padding(10.dp, 11.dp) // Set the upper, lower, and left values respectively Modifier.padding(InnerPadding(10.dp, 11.dp, 12.dp, 13.dp))// Set the upper, lower, left, and right values respectively 'Compose' extends the method 'Dp' for us in Int to help us convert to 'Dp'. // 'plus' can add another Modifier to the current Modifier. Modifier.plus(otherModifier) // Add otherModifier information to the existing modifier // 'fillMaxHeight', 'fillMaxWidth', 'fillMaxSize', similar to 'match_parent', fills the entire parent layout. Modifier.fillMaxHeight() // Fill the entire height // 'width', 'heigh', 'size' sets the width and height of the Content. Modifier.width(2.dp) // Set the width Modifier.height(3.dp) // Set the height Modifier.size(4.dp, 5.dp) // Set the height and width // 'widthIn', ' 'heightIn', 'sizeIn' sets the maximum and minimum width and height of the Content. Modifier.widthIn(2.dp) // Set the maximum width Modifier.heightIn(3.dp) // Set the maximum height Modifier.sizeIn(4.dp, 5.dp, 6.dp, 7.dp) // Set the maximum and minimum width and height // 'gravity' the position of the element in 'Column'. Modifier.gravity(Alignment.CenterHorizontally) // horizontal center Modifier.gravity(Alignment.Start) // horizontal left Modifier.gravity(Alignment.End) // the horizontal position is right // 'RTL', 'LTR' starts laying out the direction of UI. Modifier.rtl // From right to left / / Modifier to learn more: https://developer.android.com/jetpack/compose/modifiers-list Copy the code
-
Column LinearLayout ≈ Android LinearLayout-VERTICAL
-
Row HORIZONTAL layout ≈Android LinearLayout-HORIZONTAL
-
Box FrameLayout ≈Android FrameLayout, to place one element on another element, set horizontalArrangement and verticalAlignment parameters to the position of child items in Row. For Column, set verticalArrangement and horizontalAlignment
-
ConstraintLayout needs to be introduced for layout
- The introduction of
implementation "Androidx. Constraintlayout: constraintlayout - compose: 1.0.0 - beta02" Copy the code
constraintlayout-compose
Usage process
- Complete usage example
@Composable fun testConstraintLayout(a) { ConstraintLayout() { Create three references with createRefs val (imageRef, nameRef) = createRefs() Image(painter = painterResource(id = R.mipmap.test), contentDescription = "Figure", modifier = Modifier .constrainAs(imageRef) {Bind Image to imageRef by constrainAs and add a constraint top.linkTo(parent.top) start.linkTo(parent.start) bottom.linkTo(parent.bottom) } .size(100.dp) .clip(shape = RoundedCornerShape(5)), contentScale = ContentScale.Crop) Text( text = "Name", modifier = Modifier .constrainAs(nameRef) { top.linkTo(imageRef.top, 2.dp) start.linkTo(imageRef.end, 12.dp) end.linkTo(parent.end) width = Dimension.fillToConstraints } .fillMaxWidth(), fontSize = 18.sp, maxLines = 1, textAlign = TextAlign.Left, overflow = TextOverflow.Ellipsis, ) } } Copy the code
The list of
- Scrollable layout
// We can use the verticalScroll() modifier to make Column scrollable
Column (
modifier = Modifier.verticalScroll(rememberScrollState())){
messages.forEach { message ->
MessageRow(message)
}
}
Copy the code
-
However, the above layout cannot be reused, which may lead to performance problems. Here is our focus on layout, list
-
LazyColumn/LazyRow==RecylerView/listView layout, which solves the performance problem when scrolling. The difference between LazyRow and LazyRow is the layout of the list items and the scrolling direction
-
padding
LazyColumn( contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), ) { // ... } Copy the code
-
The item spacing
LazyColumn( verticalArrangement = Arrangement.spacedBy(4.dp), ) { // ... } Copy the code
-
Floating list floating titles, using LazyColumn for sticky titles, you can use the experimental stickyHeader() function
@OptIn(ExperimentalFoundationApi::class) @Composable fun ListWithHeader(items: List<Item>) { LazyColumn { stickyHeader { Header() } items(items) { item -> ItemRow(item) } } } Copy the code
-
-
Grid layout LazyVerticalGrid
@OptIn(ExperimentalFoundationApi::class) @Composable fun PhotoGrid(photos: List<Photo>) { LazyVerticalGrid( cells = GridCells.Adaptive(minSize = 128.dp) ) { items(photos) { photo -> PhotoItem(photo) } } } Copy the code
Custom layout
-
By reorganizing the base layout
-
Canvas
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawCircle( color = Color.Blue, center = Offset(x = canvasWidth / 2, y = canvasHeight / 2), radius = size.minDimension / 4)}/ / methods like drawCircle painting circle / / drawRectangle draw a rectangle Draw a line / / drawLine / / Copy the code
animation
- Animation Api selection
Other library support
-
The navigation bar
implementation("Androidx. Navigation: navigation - compose: 2.4.0 - alpha05") Copy the code
conclusion
- Compose is generally simpler and more efficient for implementing android-native layouts, which is worth learning
- The Compose writing method has a high degree of similarity with the Flutter-Dart phonetic writing layout. We will do some comparisons with the Flutter-Dart phonetic writing layout later
reference
- Developer.android.com/jetpack/com…