Jetpack Compose实战教程(六)

Jetpack Compose实战教程(六)

第六章 没有了margin,如何区分外边距?内边距?



一、前言

我们在写xml布局的时候,经常会用到android:margin属性,毕竟除了居中以外,固定位置的偏移就得用到margin,xml中我们使用margin来设置外边距,使用padding来设置内边距。但在compose中,没有了margin属性,只有一个padding,那么我们如何设置外边距和内边距呢?

二、本章目标

能熟练的使用padding来设置内边距和外边距

友情提醒,如果各位看官有不懂的代码可以先看一下之前的章节,循序渐进,如果还是有不懂的,可以给我留言

三、开始编码

请留意:以下代码都是在清单文件中设置了横屏的

3.1 特殊情况下的margin

之所以先说特殊情况下的margin,是为了防止杠精说:明明有margin啊,只是要引入一个组件而已。没错,它就是我们第四章中提到的ConstraintLayout。 compose中的约束布局用法基本和xml一致,第四章我们也进行了一些解析,这里我们就简单上代码说明一下margin的使用

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top,100.dp)
                            start.linkTo(parent.start,100.dp)
                        }.background(color = Color.Blue))
                }
            }
        }

在这里插入图片描述

3.2 使用padding设置外边距

在使用xml代码时,我们设置外边距(margin)是在子View设置的,比如有如下代码:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#ffff00">

    <RelativeLayout
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:background="#0000ff"
        android:layout_marginTop="100dp"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

这段代码产生的UI效果如下:
在这里插入图片描述
但在compose中,设置外边距恰恰是反过来的,它是在父View中设置,等价的代码写法如下:

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow).padding(top=100.dp)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }.background(color = Color.Blue))
                }
            }
        }

这时候,有好奇的小伙伴会问了,那如果我就把这个padding写到Box 里面去,会出现什么效果呢?那么我们就来实践一下

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }.background(color = Color.Blue)
                        .padding(top=100.dp)
                    )
                }
            }
        }

运行结果如下:
在这里插入图片描述
可以看到,我们移除了ConstraintLayout(父View)的padding,所以Box(子View)的外间距就没有了,而我们在Box 设置的padding是应用于Box的子View的外边距,那么我们现在来给Box添加一下子View

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }
                        .background(color = Color.Blue)
                        .padding(top = 100.dp)
                    ){
                        Box(modifier = Modifier.size(100.dp).background(color = Color.Red))
                    }
                }
            }
        }

在这里插入图片描述
这样就很好理解了吧

3.3 使用padding设置内边距

在尝试使用padding设置内边距之前,大家需要先留意一个坑,这也是为什么我上面的例子全部是用background 来说明的原因,在xml中,我们可以给一个View设置android:background属性,然后如果再设置android:alpha是可以应用到背景上的,并且不需要关心属性设置的先后顺序,比如如下代码:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#ffff00">

    <RelativeLayout
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:background="#0000ff"
        android:alpha="0.6"
        android:layout_marginTop="100dp"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

在这里插入图片描述
我们设置的颜色是蓝色,但因为设置了40%的透明度,最终和黄色的底色交融,就变成了这个灰色,但使用compose的话,必须要将alpha的属性提前,否则将失效,所以重要的话说三遍:

修饰符(Modifier)的函数调用先后顺序很重要!!

修饰符(Modifier)的函数调用先后顺序很重要!!

修饰符(Modifier)的函数调用先后顺序很重要!!

那么我们来看compose的等价代码:

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow).padding(top = 100.dp)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }
                        .alpha(0.6f) //如果这行代码放在.background之后,那么将失效
                        .background(color = Color.Blue)
                    )
                }
            }
        }

好,进入整体,为了让大家更好的理解内边距,这里我不再单纯使用background,而是添加一张图片,我们先看如下代码:

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow)
                        .padding(50.dp)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }
                        .background(color = Color.Blue)){
                        Image(painter = painterResource(id = R.mipmap.ic_person_detail_delete_unable),
                         contentDescription = null, modifier = Modifier.background(color = Color.Green)
                         .size(100.dp).padding(20.dp))
                    }
                }
            }
        }

在这里插入图片描述
但还记得我们上面说的“修饰符(Modifier)的函数调用先后顺序很重要!!” 吗?让我们来稍微改一下代码,改变一下padding的位置

BaseTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                ConstraintLayout(
                    Modifier
                        .fillMaxSize()
                        .background(color = Color.Yellow)
                        .padding(50.dp)) {
                    Box(modifier = Modifier
                        .size(200.dp)
                        .constrainAs(createRef()) {
                            top.linkTo(parent.top)
                            start.linkTo(parent.start)
                        }
                        .background(color = Color.Blue)){
                        Image(painter = painterResource(id = R.mipmap.ic_person_detail_delete_unable), 
                        contentDescription = null, modifier = Modifier.background(color = Color.Green)
                        .padding(20.dp).size(100.dp)) //我们将padding的调用提升至size之前
                    }
                }
            }
        }

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d32ece48ed2149c687b9db54413e5c24.png

由于我们在设置图片的size之前先设置了padding,所以最终Image所占据的宽高都加上了padding的值,就变成了140dp,这也是实际开发中我们最容易疏忽的地方


至此,各位看官应该可以比较熟练的运用padding来设置内外边距了,实践大于阅读,一定要去实际使用才能牢固的掌握哦!

Jetpack Compose是一个全新的Android UI工具包,可以帮助开发者更快速、更简单地构建Android应用程序的用户界面。以下是一个Jetpack Compose实战项目的简介: 项目名称:Compose Countdown Timer 项目描述:这是一个基于Jetpack Compose的倒计时计时器应用程序。用户可以设置计时器的时间,并在计时器倒计时时观看动画。 实现步骤: 1.创建一个Compose项目并添加所需的依赖项。 2.创建一个计时器组件,该组件将显示计时器的当前时间,并在计时器倒计时时触发动画。 3.创建一个设置计时器时间的组件,该组件将允许用户设置计时器的时间。 4.将计时器组件和设置时间组件组合在一起,以创建一个完整的倒计时计时器应用程序。 代码示例: ```kotlin @Composable fun CountdownTimer() { var time by remember { mutableStateOf(0) } var isRunning by remember { mutableStateOf(false) } LaunchedEffect(isRunning) { while (isRunning && time > 0) { delay(1000) time-- } } Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { if (time > 0) { Text( text = time.toString(), fontSize = 60.sp, fontWeight = FontWeight.Bold ) } else { Text( text = "Time's up!", fontSize = 60.sp, fontWeight = FontWeight.Bold ) } } } @Composable fun SetTime(onTimeSelected: (Int) -> Unit) { var time by remember { mutableStateOf(0) } Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = "Set time", fontSize = 24.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(vertical = 16.dp) ) Row( modifier = Modifier.padding(vertical = 16.dp) ) { Text( text = "Minutes:", fontSize = 18.sp, modifier = Modifier.padding(end = 8.dp) ) OutlinedTextField( value = time.toString(), onValueChange = { time = it.toIntOrNull() ?: 0 }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.width(100.dp) ) } Button( onClick = { onTimeSelected(time) }, modifier = Modifier.padding(vertical = 16.dp) ) { Text(text = "Start timer") } } } @Composable fun ComposeCountdownTimer() { var time by remember { mutableStateOf(0) } var isRunning by remember { mutableStateOf(false) } if (time == 0) { SetTime(onTimeSelected = { selectedTime -> time = selectedTime * 60 isRunning = true }) } else { CountdownTimer() } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值