Android Compose基础布局——从传统XML的视角切入了解

0 为什么要有布局

和传统XML一样,若不使用具体的布局,所有控件将堆叠在一起,无法呈现所想的视图效果。

例如,下面在界面中声明了两个文本控件,但却未用布局包裹,就会导致两个控件重叠。

@Preview
@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

一 垂直布局 Column

被Column布局包裹的控件将会垂直排列,就像传统XML中的LinearLayout将orientation设置为了vertical。

如下,用Column对控件进行包裹,便实现了垂直布局。

@Preview
@Composable
fun ArtistCardColumn() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

二 水平布局 Row

被Row布局包裹的控件将会水平排列,就像传统XML中的LinearLayout将orientation设置为了horizontal。

@Preview
@Composable
fun ArtistCardColumn() {
    Row {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

三 堆叠排列布局Box

从Box这个单词来理解这个布局的特性,Box即“箱子”,箱子中存放的物品都是堆叠或排列起来的,所以我将其称为堆叠排列布局。

Box布局的使用比较复杂,需要通过属性参数才能 实现对子控件的布局排列。下面简单介绍下Box的两个常用属性。

contentAlignment

这个属性主要用于设置Box中子控件的位置,如上下左右中。

Modifier

Modifier是Compose中各个控件最常用到的修饰属性,几乎可以为每个控件设置Modifier属性。它可以设置如同传统xml中的matchParent、padding、width、height、background等一样的效果,且可以链式调用,简化了传统xml的很多代码。

@Preview
@Composable
fun BoxTest() {
    Box(
        modifier = Modifier
            .size(300.dp)
            .background(Color.Cyan),
        contentAlignment = Alignment.BottomStart
    ) {
        Image(painter = painterResource(R.drawable.ic_launcher_background), "")
        Icon(painter = painterResource(R.drawable.ic_launcher_foreground), "")
    }
}

实际应用

我们可以利用Box布局来实现一个类似于网易云黑胶唱片的效果

效果展示

黑胶唱片旋转效果演示

代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            HelloWorldComposeTheme {
                Surface {
                    VinylRecordView()
                }
            }
        }
    }
}

// 歌曲数据类
data class Song(
    val name: String,
    val artist: String,
    val coverRes: Int,
    @RawRes val rawRes: Int
)

//当前播放歌曲
val curSong = Song("我害怕", "薛之谦", R.drawable.demo_music1, R.raw.demo_music1)

//黑胶唱片效果实现
@Preview
@Composable
fun VinylRecordView() {
    var diskRotation by remember { mutableFloatStateOf(0f) }
    val rotationSpeed = 0.042f // 每帧递增度数,可调(速度)
    val isPlaying = remember { mutableStateOf(true) }
    // 动画:黑胶旋转
    LaunchedEffect(isPlaying.value) {
        while (isPlaying.value) {
            diskRotation += rotationSpeed * 16    // 16是大致每帧毫秒
            if (diskRotation > 360f) diskRotation -= 360f
            delay(16)
        }
        // 这里不处理归零,保持在当前角度,暂停状态
    }
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight()
            .aspectRatio(1f)//裁切为正方形
            .graphicsLayer(rotationZ = diskRotation),//设置旋转动画
        contentAlignment = Alignment.Center
    ) {
        //黑胶
        Box(
            modifier = Modifier
                .clip(CircleShape)
                .background(Color.Black, CircleShape)
                .fillMaxSize(0.7f)
                .align(Alignment.Center)
        ) {
            Image(
                painter = painterResource(id = R.drawable.ic_disc),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize()
                    .clip(CircleShape)
            )
        }
        // 封面
        Box(
            modifier = Modifier
                .clip(CircleShape)
                .background(Color.White, CircleShape)
                .fillMaxSize(0.5f)
                .align(Alignment.Center)
        ) {
            Image(
                painter = painterResource(id = curSong.coverRes),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize()
                    .clip(CircleShape)
            )
        }
    }
}

四 其余布局

除了上述所提及的基础布局外,Compose还提供了很多其他的布局。如BoxWithConstraints对应xml中的ConstraintLayout;LazyVerticalGrid对应xml中的GridLayout布局等等。还有Compose提供了许多开箱即用的布局,例如ModalNavigationDrawer、TopAppBar等,只需要再进行具体的元素填充即可完成所需要的界面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值