First, what is not as direct as the official website

  • Jetpack ComposeLast year I wrote some list layouts and left them behind, said a little brother before”Nothing is as straightforward as the official website.”This is aHis blogWe are going to use Compose to write for Android, you can learn a lot about it. Next, we will follow the official website. The principle case is based on the official website, and the writing effect is higher than the official website. I won’t go into details. XML is no longer an advantage over the current popular front-end or mobile layout framework. Since Google launched it, we will learn from it.

Second, the environment

1.AndroidSdio Beta 4.2 or Canary

Version provides a nice interface preview – an instant preview of the Compose interface

2. Make sure that what you use in your project is Kotlin 1.4.21Or higher

Build. Gradle:

 buildscript {
    ext {
        compose_version = '1.0.0 - alpha04'
    }
    // Later than 1.4.12
    ext.kotlin_version = "1.4.30"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com. Android. Tools. Build: gradle: 4.2.0 - beta05'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"}}Copy the code

3. The app belowBuild. Gradle configurationAs follows:

Set the minimum API level to 21 or higher and enable Jetpack Compose in your application’s build.gradle file. Add Jetpack Compose toolkit dependencies

plugins { id 'com.android.application' id 'kotlin-android' } android { compileSdkVersion 30 defaultConfig { ApplicationId "com. Example. Jetpackcompose" minSdkVersion 21 / / minimum API level set to 21 targetSdkVersion 30 versionCode 1 or higher level VersionName "1.0" testInstrumentationRunner "androidx. Test. Runner. AndroidJUnitRunner"} buildTypes {release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility VERSION_1_8} kotlinOptions {jvmTarget = '1.8' useIR = true} buildFeatures {compose true// and in the application Build. Gradle file to enable the Jetpack composeOptions Compose} {kotlinCompilerExtensionVersion compose_version KotlinCompilerVersion dependencies' 1.4.10 '}} {implementation "org. Jetbrains. Kotlin: kotlin - stdlib: $kotlin_version" Implementation 'androidx. Core: the core - KTX: 1.3.1' implementation 'androidx. Appcompat: appcompat: 1.2.0' implementation 'com. Google. Android. Material: material: 1.2.1' implementation "androidx.com pose. The UI: UI: $compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.ui:ui-tooling:$compose_version" Implementation 'androidx. Lifecycle: lifecycle - runtime - KTX: 2.3.0 - alpha06' testImplementation 'junit: junit: 4. +' AndroidTestImplementation 'androidx. Test. Ext: junit: 1.1.2' androidTestImplementation 'androidx. Test. Espresso: espresso - core: 3.3.0'}Copy the code

Create the project mainActivity.class

package com.example.jetpackcompose
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.*
import androidx.compose.ui.platform.setContent
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello World")}}}Copy the code

Third, the Layouts

Official website address component learning

  • Next we’ll learn – how to use Compose to build a simple UI layout such asThe text.The pictureAnd so oncolumnandlineContainer layout components, whether or notFlutter,SwiftUI,HTML,Compose. Once you learn the basics of rows and columns and add a Stack, you’ll be able to handle almost all layout styles, except for details and unusual componentsSee the property,See the website,The baiduYou can use it directly.

Jetpack Compose is built around Composable functions, and all the components are composed. Just add the @composable annotation to the function name.

I. Text related attributes and cases

  • Let’s take a look at the official libraryTextAlso annotated as Composeable by @composeable. Many familiar properties are internally defined to provide developer Settings.
@Composable
fun Text(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unset,
    fontSize: TextUnit = TextUnit.Inherit,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Inherit,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Inherit,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    onTextLayout: (TextLayoutResult) - >Unit = {},
    style: TextStyle = currentTextStyle()
) {
    Text(
        AnnotatedString(text),
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        emptyMap(),
        onTextLayout,
        style
    )
}

Copy the code
  • Can’t wait to write a TextView by now?
class ComposeStudy_01 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContent{
            Text("Hello World")}}}Copy the code

With so many attributes available, try the usual colors, font sizes, borders, font styles, spacing, bold, and so on

⭐️ note here is that the default attribute can not write the parameter name according to the parameter order from top to bottom, but if you want to skip to set two or three or more need to write parameter name oh, so as to correspond to negative values, for beginners tips.

   class ComposeStudy_01 : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContent {
            Text(
                text = " Hello World"./ / ` ` border
                modifier = Modifier.border(
                    border = BorderStroke(
                        width = 3.dp,
                        color = Color(0xFF999999),
                    ),
                    shape = RoundedCornerShape(20f.60f.20f.160f),),// 'color',
                color = Color.Green,
                // 'font size',
                fontSize = TextUnit.Sp(66),
                // The thickness of the font
                fontWeight = FontWeight.Bold,
                / / italics
                fontStyle = FontStyle.Italic,
                fontFamily = FontFamily.Default,
                // Horizontal spacing of font
                letterSpacing = TextUnit.Em(0),
                // Draw a horizontal line above the text
                textDecoration = TextDecoration.LineThrough
            )
        }
    }
}
Copy the code

Two, text packaging

  • Now that Jetpack Compose is built around composable functions. So let’s write a generic text to get it through@Compose
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContent {
            myText(" Hello World")}}@Composable
    private fun myText(text:String) {
        Text(
            text = text,
            / / ` ` border
            modifier = Modifier.border(
                border = BorderStroke(
                    width = 3.dp,
                    color = Color(0xFF999999),
                ),
                shape = RoundedCornerShape(20f.60f.20f.160f),),// 'color',
            color = Color.Green,
            // 'font size',
            fontSize = TextUnit.Sp(66),
            // The thickness of the font
            fontWeight = FontWeight.Bold,
            / / italics
            fontStyle = FontStyle.Italic,
            fontFamily = FontFamily.Default,
            // Horizontal spacing of font
            letterSpacing = TextUnit.Em(0),
            // Draw a horizontal line above the text
            textDecoration = TextDecoration.LineThrough
        )
    }
Copy the code

Compose, Flutter or SwiftUI can be separated and encapsulated in other files. Below we create a new file and class folder specifically to place our UI.

Three,Modifier

  • When I useModifierWhen I was amazed, isn’t this SwiftUI? So I quickly opened Up Xcode

  • ModifierUse to decorate the Compose UI element or add behavior to it. For example, background, fill, and click event listeners can modify lines or add lines, text, or button behavior.

1.ModifierTo add click events

  • When I click to change the current font color, we see Modifier can set clickable, next we explore Modifier. When IRed when double-clicked.Green in standalone mode.

The following code: 1. Set the local variable color to green by default. 2. Double click to make it red

@Composable
fun myText(text: String) {
    var color = Color.Green
    Text(
        text = text,
        / / ` ` border
        modifier = Modifier.border(
            border = BorderStroke(
                width = 3.dp,
                color = Color(0xFF999999),
            ),
            shape = RoundedCornerShape(20f.60f.20f.160f),
        ).clickable(
            onClick = { color = Color.Yellow },
            onDoubleClick = { color = Color.Red }
        )...    
    }

Copy the code

Run the code, click the effect is as follows: can not modify the effect ah! At this point many of you who have studied Flutter and SwiftUI know that you are not refreshing the UI. In theCompose the insideWhether there is a Flutter as providedsetStateSame components.

I think for the foundation of the students modifier I am not much wordy. Here I can finally say that it is true that SwiftUI is the same as SwiftUI in terms of customization, which will be discussed and studied further in later chapters. If there is no good customization canvas, these apis will be on the same path as SwiftUI, which makes me hate it.

modifier = Modifier.clickable(
            onClick = {
                nameState.value=Color.Yellow
           },
            onDoubleClick = {
                //2. After the click, the event flows up to modify the status value
                nameState.value=Color.Red
            }
        ).background(Color.Gray,shape = RectangleShapes)
        .offset(x = Dp(10f),y=Dp(10f))
        .drawShadow(elevation = Dp(10f)),
        
        
@Stable
val RectangleShapes: Shape = object : Shape {
        val roudRect= RoundRect(10f.0f.1110f.910f.930f.160f)
        override fun createOutline(size: Size, density: Density) = Outline.Rounded(roudRect)
    }
Copy the code

Four, UI refresh –StateThe transition of

  • Anyone who has used native Android JetPack knows that LiveData and Databinding can sync with the UI,Everyone who has a Flutter knows that Flutter has a setStateweComposeAlso providesStateEtc to refresh the UI components. Due to the length of the text, we must refresh the UI, so we will use State to refresh the UI first. Later, we will have the opportunity to explain how to update the UI in detail.

Common Observable types used in the Compose application include State, LiveData, StateFlow, Flow, and Observable

Because of the habit of Flutter, people can’t help thinking of State. Here I followed the habit of Flutter and went to the official website.

✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ the Jetpack Compose, states and events are separated. Status represents values that can be changed, and events represent notifications that something has happened. By separating the state from the event, you can decouple the presentation of the state from how the state is stored and changed. ✨ ✨ ✨ ✨ ✨ ✨ `

  • Compose is built for one-way data flows. This is a design where states flow down and events flow up.

How to understand the above statement? Let’s take a look at the pictures on the official website

1. The state is the value that can be changed [data, class, set….] 2. Events [various click events, sliding events, runtime, delayed execution, etc..] 3. State [modifiable state] must be defined above, for example, Text?

//1. Status waiting events flow upward to modify the status. The state then flows down to modify the color
val nameState: MutableState<Color> = remember { mutableStateOf(Color.Green) }
Text(
    name,
    / / with the new UI
    color = nameState.value,
    ...
    //2. After the event is clicked, flow up to modify the state in 1
    onclick(`nameState.value=Color.RED`)
)

Copy the code

In this case, nameState is the state, and onclick is the event. When the click event is triggered, the namestate. value event flows up to modify the state. The state then flows down to the UI to modify the font color.

The nameState below is the state, and onclick is the event, which flows up through the namestate. value event to modify the state when the click event is triggered. The state then flows down to the UI to modify the font color.

@Composable
fun myText(text: String) {
    //1. Changeable state
    val nameState: MutableState<Color> = remember { mutableStateOf(Color.Green) }
    After modifying the state, the state flows down to modify the UI in 4
    Text(
        text = text,
        / / ` ` border
        modifier = Modifier.border(
            border = BorderStroke(
                width = 3.dp,
                color = Color(0xFF999999),
            ),
            shape = RoundedCornerShape(20f.60f.20f.160f),
        ).clickable(
            onClick = {
                //2. After the click, the event flows up to modify the status value
                nameState.value=Color.Yellow
           },
            onDoubleClick = {
                //2. After the click, the event flows up to modify the status value
                nameState.value=Color.Red
            }
        ),
        // 'color',
        //4. State flow down to modify UI display UI
        color = nameState.value,
        // 'font size',
        fontSize = TextUnit.Sp(66),
        // The thickness of the font
        fontWeight = FontWeight.Bold,
        / / italics
        fontStyle = FontStyle.Italic,
        fontFamily = FontFamily.Default,
        // Horizontal spacing of font
        letterSpacing = TextUnit.Em(0),
        // Draw a horizontal line above the text
        textDecoration = TextDecoration.LineThrough
    )
}
Copy the code

Effect: You can see that double click turns red, single player turns yellow

Five, the picture

  • Images are often used in our development, so let’s go through a wave of images. Let’s take a look at that first@PreviewThe powerful.

@PreviewThe @compose annotation will be displayed one by one in the preview, which will allow us to work on a single part of the development process and separate the display from the overall layout, providing a better way to manage and display the annotation separately.

1.Image

    @Preview(name = "studyImage")
    @Composable
    fun StudyImageView(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.head_god)
        Image(
            bitmap = imageBitmap,
            contentDescription = resources.getString(R.string.app_name),
        )
    }
Copy the code

2.Image size clipping

@Composable
fun Image(
    bitmap: ImageBitmap,
    contentDescription: String? , modifier:Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)
=
Copy the code
  • It is not found in the source codeThe size of theandtailoringAnd so on. This is the part of the setup we talked about beforemodifierLet’s set it up. Let’s try it out.
   @Preview(name = "studyImage")
    @Composable
    fun StudyImageView(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.meinv)
        Image(
            bitmap = imageBitmap,
            contentScale= ContentScale.FillBounds,
            contentDescription = resources.getString(R.string.app_name),
            modifier = Modifier
                .height(260.dp)
                .width(200.dp)
                .padding(horizontal = 30.dp,vertical = 30.dp)
                .clip(
                    RoundedCornerShape(
                        topEnd = 30.dp,
                        topStart = 30.dp,
                        bottomEnd = 30.dp,
                        bottomStart = 30.dp
                    )
                )
        )
    }
Copy the code

Click the source code and you can see that the clipping clip provided is exactly the same as SwiftUI. I’m worried about the lack of a custom View. Google developers write for IOS. You can use a “RoundedCornerShape” to test the Shape implementation. You’ll use a “RoundedCornerShape” to test the Shape implementation.

@Stable
fun Modifier.clip(shape: Shape) = graphicsLayer(shape = shape, clip = true)

Copy the code

  • We implementShapeFind all returns oneOutlineIt depends on it. Next, let’s look at the Outline class.

We find that there are many literals that provide rounded corners, border lines, etc. We also see that Generic provides path clipping. Let’s give it a try

   @Preview(name = "studyImage")
    @Composable
    fun StudyImageView(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.meinv)
        Image(
            bitmap = imageBitmap,
            contentScale= ContentScale.FillBounds,
            contentDescription = resources.getString(R.string.app_name),
            modifier = Modifier
                .height(260.dp)
                .width(200.dp)
                .padding(horizontal = 30.dp,vertical = 30.dp)
                .clip(
                    RectangleImageShapes
                )
        )
    }
   @Stable
    val RectangleImageShapes: Shape = object : Shape {
        override fun createOutline(
            size: Size,
            layoutDirection: LayoutDirection,
            density: Density
        ): Outline {
            val path= Path()
            path.moveTo(0f.0f)
            path.relativeLineTo(20f.20f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.relativeCubicTo(40f.40f.60f.60f, -20f.130f)
            path.lineTo(size.width,size.height)
            path.lineTo(size.width,0f)
            path.close()
            return Outline.Generic(path)
        }
    }
Copy the code

Here’s what it looks like. – It’s up to you to cut your dick.

3.Image and other componentsrotating,translation,The zoom,Distortion of transformation,modified,Click on the drag and dropEtc.

Of course, images and other parts can be rotated, panted, scaled, distorted, modified, click and drag, etc., through Modifer. Now let’s do a little rotation and drag.

After code will often appear a bunch of Modifer how to do? It’s more comfortable to extract and pack

     @Preview(name = "studyImage")
    @Composable
    fun StudyImageView(a) {
        val draggerOffset:MutableState<Float> = remember{ mutableStateOf(0f)}val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.meinv)
        Image(
            bitmap = imageBitmap,
            contentScale = ContentScale.FillBounds,
            contentDescription = resources.getString(R.string.app_name),
            modifier = Modifier.ImageModifier(draggerOffset)
        )
    }

    private fun Modifier.ImageModifier(draggerOffset: MutableState<Float>):Modifier =
        composed { Modifier
            .height(260.dp)
            .width(200.dp)
            .padding(horizontal = 30.dp, vertical = 30.dp)
            .clip(
                RectangleImageShapes
            )
            .rotate(10f)
            .draggable(state = DraggableState(onDelta = {
                draggerOffset.value = +it
                Log.e("ondelta"."StudyImageView: " + draggerOffset.value)
            }), orientation = Orientation.Horizontal)
            .offset(x = draggerOffset.value.dp) 
          }

Copy the code

The effect is as follows:

Six, the layout of the placement

1.RowRows, as layout container components, are some of the simplest and most used components of every mobile API. The interior will be arranged horizontally from left to right.

    @Preview(name = "text1")
    @Composable
    fun StudyLayoutViews(a) {
        Row() {
            Text(First column,fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Red))
            Text("Second column",fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Green))
            Text("Column three?",fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Blue))

        }
    }
Copy the code

2,RowRows, as layout container components, are some of the simplest and most used components of every mobile API. The interior will be arranged vertically from top to bottom.

 Column() {
            Text( First column,fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Red))
            Text( "Second column",fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Green))
            Text( "Third column",fontSize = 22.sp,color = Color.White,modifier = Modifier.background(Color.Blue))
        }
Copy the code

3,Zhang Fengjie special lieThe FlutterUnit

  • I saw his creation in Lord Terry’s Article on FlutterFlutterUnitIt’s pretty, so let’s try it outComposeTo mimic a wave.

  • The Item analysis

This Item is analyzed from Row and Colum. Row is divided into three contents: picture, Colunm and Icon. Colunm in the middle is divided into three lines.

    @Preview(name = "text1")
    @Composable
    fun StudyLayoutViews(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.meinv)
        val delectedIcon: ImageBitmap = ImageBitmap.imageResource(R.drawable.delected_icon)
        Box(
            modifier = Modifier
                .background(Color(206.236.250))
                .padding(10.dp)
        ) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Image(
                    bitmap = imageBitmap,
                    contentDescription = "w",
                    contentScale = ContentScale.FillBounds,
                    modifier = Modifier
                        .height(50.dp)
                        .width(50.dp)
                        .background(Color.White, shape = CircleShape)
                        .padding(3.dp)
                        .clip(
                            CircleShape
                        )
                        .shadow(elevation = 150.dp, clip = true)
                )
                Column(modifier = Modifier.padding(start = 5.dp)) {
                    Text(
                        "Container",
                        fontSize = 16.sp,
                        color = Color.Black,
                    )
                    Text(
                        "Container component",
                        modifier = Modifier.padding(top = 3.dp, bottom = 3.dp),
                        fontSize = 12.sp,
                        color = Color.Gray,
                    )
                    Text(
                        "1.23 million views",
                        fontSize = 8.sp,
                        color = Color.White,
                    )
                }
                Box(
                    modifier = Modifier
                        .height(60.dp)
                        .padding(start = 30.dp),
                    contentAlignment = Alignment.BottomCenter
                ) {
                    Image(
                        bitmap = delectedIcon,
                        contentDescription = "w",
                        contentScale = ContentScale.FillBounds,
                        modifier = Modifier
                            .height(20.dp)
                            .width(20.dp)
                            .shadow(elevation = 150.dp, clip = true)}}}}Copy the code

Here we have learned the basic layout arrangement, of course, the border is still a gap, must be custom drawing trimmed border. Let’s take a look at Compose’s tailoring again.

The Size provided in Shaper is the Size of the entire component, which is then clipped to the canvas by forming corresponding boxes.

As for the custom is not skilled can see Zhang Fengjie special strong or my article

 @Stable
    val BoxClipShapes: Shape = object : Shape {
        override fun createOutline(
            size: Size,
            layoutDirection: LayoutDirection,
            density: Density
        ): Outline {
            val path = Path()
            path.moveTo(20f.0f)
            path.relativeLineTo(-20f.20f)
            path.relativeLineTo(0f,size.height - 40f)
            path.relativeLineTo(20f.20f)
            path.relativeLineTo(size.width / 3f-20.0f)
            path.relativeLineTo(15f, -20f)
            path.relativeLineTo(size.width / 3f-30.0f)
            path.relativeLineTo(15f.20f)
            path.relativeLineTo(size.width / 3f-20.0f)
            path.relativeLineTo(20f, -20f)
            path.relativeLineTo(0f, -(size.height - 40f))
            path.relativeLineTo(-20f, -20f)
            path.close()

            return Outline.Generic(path)
        }
    }
Copy the code

Can’t wait to see the effect?

I’m not going to draw the stars. I mean, have you practiced your tailoring here? No, I don’t think it’s the same up here. Let’s do the upside.

    @Stable
    val BoxClipShapes: Shape = object : Shape {
        override fun createOutline(
            size: Size,
            layoutDirection: LayoutDirection,
            density: Density
        ): Outline {
            val path = Path()
            path.moveTo(20f.0f)
            path.relativeLineTo(-20f.20f)
            path.relativeLineTo(0f,size.height - 40f)
            path.relativeLineTo(20f.20f)
            path.relativeLineTo(size.width / 3f-20.0f)
            path.relativeLineTo(15f, -20f)
            path.relativeLineTo(size.width / 3f-30.0f)
            path.relativeLineTo(15f.20f)
            path.relativeLineTo(size.width / 3f-20.0f)
            path.relativeLineTo(20f, -20f)
            path.relativeLineTo(0f, -(size.height - 40f))
            path.relativeLineTo(-20f, -20f)
            path.relativeLineTo(-(size.width / 3f-20),0f)
            path.relativeLineTo(-15f.20f)
            path.relativeLineTo(-(size.width / 3f-30), 0f)
            path.relativeLineTo(-15f, -20f)
            path.close()

            return Outline.Generic(path)
        }
    }
Copy the code

The effect is ok as follows of course clinking coquetty, see design personnel can design a flower to come can go.

  • We see a dark border. Let’s give it a tryContainer Box Box Modifier set border.
Box(modifier = Modifier.padding(20.dp)
.clip(BoxClipShapes)
.background(Color(206.236.250))
.border(width=1.dp,color = Color.Blue))
Copy the code

⭐️⭐ ⭐ ⭐ ⭐️ demoral100 ️ the effect is as follows. Why not the middle and the sides? If we look at the border source code, it is just a rectangle, but we ruthlessly cropped out the middle and two corners. ⭐ ️ ⭐ ️ ⭐ ️ ⭐ ️

Now that we’ve clipped and the border provides the clipping shaper can we clipping the Box to the border and clipping the same?


 Box(modifier = Modifier.padding(20.dp)
.clip(BoxClipShapes)
.background(Color(206.236.250))
.border(width=1.dp,color = Color(79.129.160),shape = BoxBorderClipShape)){contents}Copy the code

There must be someone else who says otherwise. Code to see the effect:

We can see that part of the upper part is blue. In fact, if we look at the whole, another Box at the bottom is also cut, but there is no Box at the top that is cut synchronically. Is it possible to complete this effect by installing a Box inside that is cut both at the top and bottom?

@Preview(name = "text1") @Composable fun StudyLayoutViews() { val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.meinv) val delectedIcon: ImageBitmap = ImageBitmap.imageResource(R.drawable.delected_icon) Box(modifier = Modifier.clip(BoxBorderClipShape) .background(Color(89, 199, 249))) { Box( modifier = Modifier.padding(0.dp).clip(BoxClipShapes) .background(Color(206, 236, 250)) .border(width = 1.dp, color = Color(89, 199, 249), shape = BoxClipShapes) ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(10.dp) ) { Image( bitmap = imageBitmap, contentDescription = "w", contentScale = ContentScale.FillBounds, modifier = Modifier .height(50.dp) .width(50.dp) .background(Color.White, shape = CircleShape) .padding(3.dp) .clip( CircleShape ) .shadow(elevation = 150.dp, clip = true) ) Column(modifier = Modifier.padding(start = 5.dp)) { Text( "Container", fontSize = 16.sp, Padding (top = 1.dp, bottom = 2.dp), fontSize = 12.sp, Color = color.gray,) Text(" 1.23 million read ", fontSize = 8.sp, color = color.white, ) } Box( modifier = Modifier .height(60.dp) .padding(start = 30.dp, end = 5.dp), contentAlignment = Alignment.BottomCenter ) { Image( bitmap = delectedIcon, contentDescription = "w", modifier = Modifier .height(16.dp) .width(13.dp) .shadow(elevation = 150.dp, clip = true) ) } } } } }Copy the code

Now we should have no problems with SwiftUi’s fancy clipping, which is Compose? The problem is that you’re not familiar with customization. Of course you can check out my blog or any other author’s blog. You think this is the end of it? Next to enter the topic of custom drawing, cutting in the development is far from meeting the needs of such as curves or broken line charts.

Compose- Custom drawing

  • For those unfamiliar with the basics of customization and related apis, check out my blog

In Compose most of the API in androidx.com pose. The UI. The graphics, interested can look at.

1.Android Custom – Gradient filling curve 2.Android Custom – Gesture scaling Curve line figure 3. Art is drawing 5. Drawing related API….

  • Do you think I’m going to fake it like these blogs? In the code. I couldn’t help writing a hint
@Preview(name = "MyLineView") @Composable fun MyLineView(){ Canvas( modifier = Modifier.padding(10.dp).width(200.dp).height(100.dp), ){ drawIntoCanvas {canvas-> val paint=Paint() paint.color=Color.Gray paint.style= PaintingStyle.Stroke //1. Translate (0f,size.height) Canvas. Scale (1f,-1f) //2. PathY =Path() pathY. MoveTo (0f,0f) relativeLineTo(0f,size.height) canvas. DrawPath (paint)}}Copy the code

Draw the X axis

Draw the line

  • Drawing has also been roughly browsed through the basic drawing is still available. Draw text not found….. Awkward as hell
@Preview(name = "MyLineView") @Composable fun MyLineView(bitmap: ImageBitmap){ Canvas( modifier = Modifier .padding(10.dp) .width(200.dp) .height(100.dp), ){canvas-> val paint= paint () paint. Color = color (208,208,208) paint. Style = paintingstyle.stroke paint.strokeWidth=3f val paintFill=Paint() paintFill.color=Color.Gray paintFill.style= PaintingStyle.Stroke paintFill.strokeWidth=3f //1. Draw the coordinate axis Canvas.translate (0f, sie.height) Canvas.scale (1f,-1f) //2. PathY =Path() pathY. MoveTo (0f,0f).Relativelineto (0f,size.height) Canvas. DrawPath (paint) //2 Val pathX =Path() pathx.moveto (0f,0f) pathx.relativelineto (sie.width,0f) canvas. DrawPath (pathX,paint) val dataList:MutableList<Offset> = mutableListOf(Offset(20f,60f),Offset(40f,30f),Offset(50f,34f),Offset(80f,54f),Offset(100f,34f),Offset(200f,134f),Offset( 400f,154f),Offset(480f,134f)) val linePath=Path() paint.color=Color.Blue val colors:MutableList<Color> = mutableListOf(Color.Red,Color.Blue,Color.Green) paint.shader= LinearGradientShader(Offset(0f,0f),Offset(size.width,0f),colors,null,TileMode.Clamp) paint.isAntiAlias=true //3. For (index in 0 until dataList. Size){linePath. LineTo (dataList[index].x,dataList[index].y)} LinePath. LineTo (dataList[dataList. Sie-1].x,0f) linePath. Close () // Draw the Fill paintFill. Style = paintingstyle.fill paintFill.shader= LinearGradientShader(Offset(0f,size.height),Offset(0f,0f), ArrayListOf (Color (59157254161), Color (59157254,)), null, TileMode. Clamp) canvas. DrawPath (linePath paintFill) Val line =Path() for (index in 0 until dataList. Size){line.lineto (dataList[index].x,dataList[index].y)} val line =Path() for (index in 0 until dataList. Paint. Style = paintingstyle. Stroke canvas. DrawPath (line,paint) //3 Paint until dataList.size){ canvas.drawCircle(Offset(dataList[index].x,dataList[index].y),6f,paint) } canvas.drawImage(image =  bitmap, Offset(100f,100f),paint) } } }Copy the code

Here we learned not only about layout, but also about custom parts. I’m sure you’ll be fine when your product UI comes up with the weirdest look.

List four,

Official website address component learning

  • Compose can be combined with Column and RowrepateThe default Column and Row cannot be swiped out of the screen. Of course, it can be used with ModiferverticalScrollandhorizontalScrollSlide content Settings.
  @Composable
  fun ListStudy(a) {
        // Set sliding
        val scrollState = rememberScrollState()
        Column(modifier = Modifier.verticalScroll(scrollState)) {
            // Iterate over the inner Item of the loop
            repeat(100) {
                Row(
                    modifier = Modifier
                        .padding(10.dp)
                        .fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    StudyLayoutViews()
                    Spacer(modifier = Modifier.padding(horizontal = 5.dp))
                    StudyLayoutViews()

                }
            }
        }
    }

Copy the code

  • LazyColumn

When the data is variable enough to cause performance problems, we can use LazyColumn.

Use as follows:

LazyColumn(state = scrollState) {
        items(100) {contents..... }}Copy the code

    @Composable
    fun ListStudy(a) {
        // Set sliding
        val scrollState = rememberScrollState()
        val scrollLazyState = rememberLazyListState()
        LazyColumn(state = scrollLazyState) {
            // Iterate over the inner Item of the loop
            items(100) {
                Row(
                    modifier = Modifier
                        .padding(10.dp)
                        .fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    StudyLayoutViews()
                    Spacer(modifier = Modifier.padding(horizontal = 5.dp))
                    StudyLayoutViews()

                }
            }
        }
    }
Copy the code

Here we have combined the official website to learn not only basic UI components and container list components but also a wave of custom clipping and drawing. Compose has a lot of content to try out, animations, state updates, etc… And then we’ll write an example to finish it off perfectly.

Five, the case

  • Can you finish the following interface in 10 minutes? Probably not. Looks like there’s a custom section again. So let’s start with the case.

1. Upper part of the picture

1. A curved image has an emission circle at the top. 2. Bottom radian picture cropping. 3. Emissive disk at the top.

  • Radian pictures
  @Stable
    class QureytoImageShapes(var hudu: Float = 100f) : Shape {

        override fun createOutline(
            size: Size,
            layoutDirection: LayoutDirection,
            density: Density
        ): Outline {
            val path = Path()
            path.moveTo(0f.0f)
            path.lineTo(0f, size.height-hudu)
            path.quadraticBezierTo(size.width/2f, size.height, size.width, size.height-hudu)
            path.lineTo(size.width,0f)
            path.close()
            return Outline.Generic(path)
        }
    }

Copy the code
  @Preview(name = "login")
    @Composable
    fun LoginPage(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.head_god)
        val delectedIcon: ImageBitmap = ImageBitmap.imageResource(R.drawable.hean_lhc)
        Box(contentAlignment = Alignment.Center) {
            Image(
                bitmap = imageBitmap,
                contentDescription = "",
                contentScale=ContentScale.FillWidth,
                modifier = Modifier.fillMaxWidth().height(280.dp).clip(QureytoImageShapes(160f))
            )
            Image(bitmap = delectedIcon, contentDescription = "")}}Copy the code

  • The emissive disc at the top

The bottom is translucent colored circle, the top is cut round picture has written above the Border. Do it again

    @Preview(name = "login")
    @Composable
    fun LoginPage(a) {
        val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.head_god)
        val delectedIcon: ImageBitmap = ImageBitmap.imageResource(R.drawable.hean_lhc)
        Box(contentAlignment = Alignment.Center) {
            Image(
                bitmap = imageBitmap,
                contentDescription = "",
                contentScale=ContentScale.FillWidth,
                modifier = Modifier.fillMaxWidth().height(230.dp).clip(QureytoImageShapes(160f))
            )
            Box(
                contentAlignment=Alignment.Center,
                modifier = Modifier
                    .padding(0.dp)
                    .clip(CicleImageShape)
                    .background(Color(206.236.250.121))
                    .width(130.dp)
                    .height(130.dp)
            ){
                Image(
                    bitmap = imageBitmap,
                    contentDescription = "w",
                    contentScale = ContentScale.FillBounds,
                    modifier = Modifier
                        .height(80.dp)
                        .width(80.dp)
                        .background(color = Color(0XFF0DBEBF), shape = CircleShape)
                        .padding(3.dp)
                        .clip(
                            CircleShape
                        )
                        .shadow(elevation = 150.dp, clip = true)}}}Copy the code

2. Middle text

 Box(contentAlignment = Alignment.Center,modifier = Modifier
                .fillMaxWidth()
                .padding(top =20.dp)) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(text = "ComposeUnit landing",fontSize = 18.sp)
                    Text(text = "More exciting, more experience ~",fontSize = 12.sp,color = Color.Gray)

                }
            }
Copy the code

3. Input box

 Box(contentAlignment = Alignment.Center, modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 30.dp)
            ) {
                TextField(
                    value = " ConmposeUnit",
                    onValueChange = { },
                    shape = RoundedCornerShape(18.dp),
                    colors = textFieldColors(
                        unfocusedIndicatorColor = Color.Transparent,
                        backgroundColor = Color.White

                    ),
                    modifier = Modifier.border(
                        1.dp,
                        Color(111.111.111.66),
                        shape = RoundedCornerShape(18.dp)
                    ),
                    leadingIcon = { Icon(bitmap = deIcon, contentDescription = "")})}Copy the code

4. Select status and underline Settings

  • Text we can start with background clipping. Don’t question the code
  Box( modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 20.dp)
            ) {
                Row(
                    horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier
                        .fillMaxWidth()
                        .padding(  horizontal = 50.dp ,vertical = 20.dp)) {
                            Checkbox(
                                checked = true,
                                onCheckedChange = { },
                                colors = CheckboxDefaults.colors(checkedColor = Color(0XFF0DBEBF))
                            )
                            Text("User Registration",color=Color(0XFF0DBEBF),modifier = Modifier.border(1.dp,color=Color(0XFF0DBEBF), Shape = LineUndFunction))}} underline Settingsval LineUndFunction:Shape = object :Shape{
        override fun createOutline(
            size: Size,
            layoutDirection: LayoutDirection,
            density: Density
        ): Outline {
            val path=Path()
            path.moveTo(0f,size.height-2f)
            path.lineTo(size.width,size.height-2f)
            path.lineTo(size.width,size.height)
            path.lineTo(0f,size.height)
            path.close()
            return Outline.Generic(path)
        }

    }

Copy the code

conclusion

Compose is basically SwiftUI, which is similar to Flutter. It can create the same efficiency as Flutter, and supports excellent compatibility with SwiftUI. However, Kotlin’s various sets of higher-order functions make it difficult for beginners to read the source code, and I will write a series of articles carefully later To some things or I write a question please praise comments, hope to learn together. My QQ learning skirt 730772561