《Jetpack Compose从入门到实战》第三章 定制 UI 视图

这篇具有很好参考价值的文章主要介绍了《Jetpack Compose从入门到实战》第三章 定制 UI 视图。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

《Jetpack Compose从入门到实战》第三章 定制 UI 视图,安卓,ui,android

配置颜色、字体与形状

-ui.theme.Color.kt

val pink100 = Color(0xFFFFF1F1)
val pink900 = Color(0xFF3F2C2C)
val white = Color(0xFFFFFFFF)
val white850 = Color(0xD9FFFFFF)
val gray = Color(0xFF232323)
  • ui.theme.Type.kt
    先将Nunito Sans字体家族放入 res/font,再根据设计稿写代码
val nunitoSansFamily = FontFamily(
    Font(R.font.nunitosans_light, FontWeight.Light),
    Font(R.font.nunitosans_semibold, FontWeight.SemiBold),
    Font(R.font.nunitosans_bold, FontWeight.Bold)
)

val h1 = TextStyle(
    fontSize = 18.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.Bold
)
val h2 = TextStyle(
    fontSize = 14.sp,
    letterSpacing = 0.15.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.Bold
)
val subtitle1 = TextStyle(
    fontSize = 16.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.Light
)
val body1 = TextStyle(
    fontSize = 14.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.Light
)
val body2 = TextStyle(
    fontSize = 12.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.Light
)
val button = TextStyle(
    fontSize = 14.sp,
    letterSpacing = 1.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.SemiBold,
    color = white
)
val caption = TextStyle(
    fontSize = 12.sp,
    fontFamily = nunitoSansFamily,
    fontWeight = FontWeight.SemiBold
)
  • ui.theme/Shape.kt

Welcome Page

@Preview(showBackground = true)
@Composable
fun WelcomeTitle() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_logo)),
            contentDescription = "weclome_logo",
            modifier = Modifier
                .wrapContentWidth()
                .height(32.dp)
        )
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(32.dp),
            contentAlignment = Alignment.BottomCenter
        ) {
            Text(
                text = "Beautiful home garden solutions",
                textAlign = TextAlign.Center,
                style = subtitle1,
                color = gray
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun WelcomeButtons() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ){
        Button(
            onClick = { },
            modifier = Modifier
                .height(48.dp)
                .padding(horizontal = 16.dp)
                .fillMaxWidth()
                .clip(medium),
            colors = ButtonDefaults.buttonColors(backgroundColor = pink900)
        ) {
            Text(
                text = "Create account",
                style = button,
                color = white
            )
        }
        Spacer(modifier = Modifier.height(24.dp))
        TextButton(
            onClick = { },
        ) {
            Text(
                text = "Log in",
                style = button,
                color = pink900,
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun LeafImage() {
    Image(
        painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_welcome_illos)),
        contentDescription = "weclome_illos",
        modifier = Modifier
            .wrapContentSize()
            .padding(start = 88.dp)
    )
}

@Preview(showBackground = true)
@Composable
fun WelcomeContent() {
    Column(modifier = Modifier
        .fillMaxSize()
    ) {
        Spacer(Modifier.height(72.dp))
        LeafImage()
        Spacer(modifier = Modifier.height(48.dp))
        WelcomeTitle()
        Spacer(modifier = Modifier.height(40.dp))
        WelcomeButtons()
    }
}

@Composable
fun WelcomePage() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(pink100)
    ) {
        Image(
            painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_welcome_bg)),
            contentDescription = "weclome_bg",
            modifier = Modifier.fillMaxSize()
        )
        WelcomeContent()
    }
}

Login Page

@Preview(showBackground = true)
@Composable
fun TopText() {
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceBetween
    ) {
        var keywordPre = "By Clicking below you agree to our".split(" ")
        var keywordPost = "and consent".split(" ")
        for (word in keywordPre) {
            Text(
                text = word,
                style = body2,
                color = gray,
            )
        }
        Text(
            text = "Terms of Use",
            style = body2,
            color = gray,
            textDecoration = TextDecoration.Underline
        )
        for (word in keywordPost) {
            Text(
                text = word,
                style = body2,
                color = gray,
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun BottomText() {
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.Center
    ) {
        Text(text = " to Our ",
            style = body2,
            color = gray
        )
        Text(text = "Privacy Policy.",
            style = body2,
            color = gray,
            textDecoration = TextDecoration.Underline
        )
    }
}

@Preview(showBackground = true)
@Composable
fun HintWithUnderline() {
    Column(
        modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 16.dp)
    ){
        TopText()
        BottomText()
    }
}

@Preview(showBackground = true)
@Composable
fun LoginInputBox() {
    Column {
        OutlinedTextField(
            value = "",
            onValueChange = {},
            modifier = Modifier
                .fillMaxWidth()
                .height(56.dp)
                .clip(small),
            placeholder = {
                Text(
                    text = "Email address",
                    style = body1,
                    color = gray
                )
            }
        )
        Spacer(modifier = Modifier.height(8.dp))
        OutlinedTextField(
            value = "",
            onValueChange = {},
            modifier = Modifier
                .fillMaxWidth()
                .height(56.dp)
                .clip(small),
            placeholder = {
                Text(
                    text = "Password(8+ Characters)",
                    style = body1,
                    color = gray
                )
            }
        )
    }
}

@Preview(showBackground = true, showSystemUi = false)
@Composable
fun LoginTitle() {
    Text(
        text = "Log in with email",
        modifier = Modifier
            .fillMaxWidth()
            .paddingFromBaseline(top = 184.dp, bottom = 16.dp),
        style = h1,
        color = gray,
        textAlign = TextAlign.Center
    )
}

@Preview(showBackground = true)
@Composable
fun LoginButton() {
    Button(
        onClick = { },
        modifier = Modifier
            .height(48.dp)
            .fillMaxWidth()
            .clip(medium),
        colors = ButtonDefaults.buttonColors(backgroundColor = pink900)
    ) {
        Text(
            text = "Log in",
            style = button,
            color = white
        )
    }
}

@Composable
fun LoginPage() {
    Column(
        Modifier
            .fillMaxSize()
            .background(white)
            .padding(horizontal = 16.dp)
    ) {
        LoginTitle()
        LoginInputBox()
        HintWithUnderline()
        LoginButton()
    }
}

@Composable
@Preview
fun LoginPageLightPreview() {
    BloomTheme() {
        LoginPage()
    }
}

Home Page

val small = RoundedCornerShape(4.dp)
val medium = RoundedCornerShape(24.dp)

val shapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(4.dp),
    large = RoundedCornerShape(0.dp)
)
data class ImageItem(val name: String, val resId: Int)

val bloomBannerList = listOf(
    ImageItem("Desert chic", R.drawable.desert_chic),
    ImageItem("Tiny terrariums", R.drawable.tiny_terrariums),
    ImageItem("Jungle Vibes", R.drawable.jungle_vibes)
)

val bloomInfoList = listOf(
    ImageItem("Monstera", R.drawable.monstera),
    ImageItem("Aglaonema", R.drawable.aglaonema),
    ImageItem("Peace lily", R.drawable.peace_lily),
    ImageItem("Fiddle leaf tree", R.drawable.fiddle_leaf),
    ImageItem("Desert chic", R.drawable.desert_chic),
    ImageItem("Tiny terrariums", R.drawable.tiny_terrariums),
    ImageItem("Jungle Vibes", R.drawable.jungle_vibes)
)

val navList = listOf(
    ImageItem("Home", R.drawable.ic_home),
    ImageItem("Favorites", R.drawable.ic_favorite_border),
    ImageItem("Profile", R.drawable.ic_account_circle),
    ImageItem("Cart", R.drawable.ic_shopping_cart)
)

@Preview(showBackground = true)
@Composable
fun BloomRowBanner() {
    Column {
        Box(
            Modifier.fillMaxWidth()
        ) {
            Text(
                text = "Browse themes",
                style = h1,
                color = gray,
                modifier = Modifier
                    .fillMaxWidth()
                    .paddingFromBaseline(top = 32.dp)
            )
        }
        Spacer(modifier = Modifier.height(16.dp))
        LazyRow(
            modifier = Modifier.height(136.dp)
        ) {
            items(bloomBannerList.size) {
                if (it != 0) {
                    Spacer(modifier = Modifier.width(8.dp))
                }
                PlantCard(bloomBannerList[it])
            }
        }
    }
}


@Preview(showBackground = true)
@Composable
fun BloomInfoList() {
    Column {
        Row(
            Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(
                text = "Design your home garden",
                style = h1,
                color = gray,
                modifier = Modifier.paddingFromBaseline(top = 40.dp)
            )
            Icon(
                painterResource(id = R.drawable.ic_filter_list),
                "filter",
                modifier = Modifier
                    .padding(top = 24.dp)
                    .size(24.dp)
            )
        }
        Spacer(modifier = Modifier.height(16.dp))
        LazyColumn(
            modifier = Modifier
                .fillMaxWidth(),
            contentPadding = PaddingValues(bottom = 56.dp)
        ) {
            items(bloomInfoList.size) {
                if (it != 0) {
                    Spacer(modifier = Modifier.height(8.dp))
                }
                DesignCard(bloomInfoList[it])
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun SearchBar() {
    Box {
        TextField(
            value = "",
            onValueChange = {},
            modifier = Modifier
                .fillMaxWidth()
                .height(56.dp)
                .clip(RoundedCornerShape(4.dp))
                .border(BorderStroke(1.dp, Color.Black)),
            leadingIcon = {
                Icon(
                    painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_search)),
                    contentDescription = "search",
                    modifier = Modifier.size(18.dp)
                )
            },
            placeholder = {
                Text(
                    text = "Search",
                    style = body1,
                    color = gray
                )
            },
            colors = TextFieldDefaults.outlinedTextFieldColors(
                backgroundColor = white,
                unfocusedBorderColor = white,
                focusedBorderColor = white,
            ),
        )
    }
}

@Composable
fun HomePage() {
    Scaffold(
        bottomBar = {
            BottomBar()
        }
    ) {
        Column(
            Modifier
                .fillMaxSize()
                .background(white)
                .padding(horizontal = 16.dp)
        ) {
            Spacer(modifier = Modifier.height(40.dp))
            SearchBar()
            BloomRowBanner()
            BloomInfoList()
        }
    }
}

@Composable
fun DesignCard(plant: ImageItem) {
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            painterResource(id = plant.resId),
            contentScale = ContentScale.Crop,
            contentDescription = "image",
            modifier = Modifier
                .size(64.dp)
                .clip(RoundedCornerShape(4.dp))
        )
        Spacer(modifier = Modifier.width(16.dp))
        Column {
            Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                Column {
                    Text(
                        text = plant.name,
                        style = h2,
                        color = gray,
                        modifier = Modifier.paddingFromBaseline(top = 24.dp)
                    )
                    Text(
                        text = "This is a description",
                        style = body1,
                        color = gray,
                        modifier = Modifier
                    )
                }
                Checkbox(
                    modifier = Modifier
                        .padding(top = 24.dp)
                        .size(24.dp),
                    checked = false,
                    onCheckedChange = {
                        // plant.enable = it
                    },
                    colors = CheckboxDefaults.colors(
                        checkmarkColor = white
                    )
                )
            }
            Divider(color = gray, modifier = Modifier.padding(top = 16.dp), thickness = 0.5.dp)
        }
    }
}


@Composable
fun PlantCard(plant: ImageItem) {
    Card(
        modifier = Modifier
            .size(136.dp)
            .clip(RoundedCornerShape(4.dp))
    ) {
        Column {
            Image(
                painterResource(id = plant.resId),
                contentScale = ContentScale.Crop,
                contentDescription = "image",
                modifier = Modifier
                    .fillMaxWidth()
                    .height(96.dp)
            )
            Box(
                Modifier
                    .fillMaxWidth()
                    .padding(start = 16.dp)
            ) {
                Text(
                    text = plant.name,
                    style = h2,
                    color = gray,
                    modifier = Modifier
                        .fillMaxWidth()
                        .paddingFromBaseline(top = 24.dp, bottom = 16.dp)
                )
            }
        }
    }
}

@Composable
fun BottomBar() {
    BottomNavigation(
        elevation = 16.dp,
        modifier = Modifier
            .fillMaxWidth()
            .height(56.dp)
            .background(pink100)
    ) {
        navList.forEach {
            BottomNavigationItem(
                onClick = {},
                icon = {
                    Icon(
                        painterResource(id = it.resId),
                        contentDescription = null,
                        modifier = Modifier.size(24.dp),
                    )
                },
                label = {
                    Text(
                        it.name,
                        style = caption,
                        color = gray,
                    )
                },
                selected = ("Home" == it.name)
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun BottomBarPreview() {
    BloomTheme() {
        BottomBar()
    }
}

@Preview(showBackground = true)
@Composable
fun DesignCardPreview() {
    BloomTheme() {
        DesignCard(bloomInfoList[0])
    }
}

@Preview(showBackground = true)
@Composable
fun PlantCardPreview() {
    BloomTheme() {
        PlantCard(bloomBannerList[0])
    }
}

@Preview(showBackground = true)
@Composable
fun HomePageLightPreview() {
    BloomTheme() {
        HomePage()
    }
}

主题

private val BloomLightColorPaltte = lightColors(
    primary = pink100,
    secondary = pink900,
    background = white,
    surface = white850,
    onPrimary = gray,
    onSecondary = white,
    onBackground = gray,
    onSurface = gray,
)

private val BloomDarkColorPaltte = darkColors(
    primary = green900,
    secondary = green300,
    background = gray,
    surface = white150,
    onPrimary = white,
    onSecondary = gray,
    onBackground = white,
    onSurface = white850
)

open class WelcomeAssets private constructor(
    var background: Int,
    var illos: Int,
    var logo: Int
) {
    object LightWelcomeAssets : WelcomeAssets(
        background = R.drawable.ic_light_welcome_bg,
        illos = R.drawable.ic_light_welcome_illos,
        logo = R.drawable.ic_light_logo
    )

    object DarkWelcomeAssets : WelcomeAssets(
        background = R.drawable.ic_dark_welcome_bg,
        illos = R.drawable.ic_dark_welcome_illos,
        logo = R.drawable.ic_dark_logo
    )
}

internal var LocalWelcomeAssets = staticCompositionLocalOf { WelcomeAssets.LightWelcomeAssets as WelcomeAssets }

val MaterialTheme.welcomeAssets
    @Composable
    @ReadOnlyComposable
    get() = LocalWelcomeAssets.current

enum class BloomTheme {
    LIGHT, DARK
}


@Composable
fun BloomTheme(theme: BloomTheme = BloomTheme.LIGHT, content: @Composable() () -> Unit) {
    CompositionLocalProvider(
        LocalWelcomeAssets provides if (theme == BloomTheme.DARK) WelcomeAssets.DarkWelcomeAssets else WelcomeAssets.LightWelcomeAssets,
    ) {
        MaterialTheme(
            colors = if (theme == BloomTheme.DARK) BloomDarkColorPaltte else BloomLightColorPaltte,
            typography = bloomTypoGraphy,
            shapes = shapes,
            content = content
        )
    }
}

CompositionLocal

CompositionLocal 是 Jetpack Compose 中的一种数据传递方式。它可以在组合组件之间传递可变数据,而无需通过 props 或 state 管理器来传递数据。这个特性比传统的数据传递方式更为高效和方便。
例如,我们可以通过 CompositionLocal 在应用程序的不同部分中传递数据,如主题、语言环境、字体等。这个特性可以让我们在组合应用程序中更轻松地使用全局状态,而不必每次都传递数据。
此外,CompositionLocal 还可以用于实现本地化和自定义主题等功能的高效性。因此,它是 Jetpack Compose 中非常重要的一个组成部分。

  • 如果CompositonLocal提供得知发生更改的可能性很小或永远无法改变,利用staticCompositionLocal能显著提升性能

总结

  • 所有视图组件建议用顶级函数声明

随笔:

  • 简历 遇到什么问题,用了什么方法,如何进行优化

《Jetpack Compose从入门到实战》第一章 全新的 Android UI 框架

《Jetpack Compose从入门到实战》 第二章 了解常用UI组件

《Jetpack Compose从入门到实战》第三章 定制 UI 视图

《Jetpack Compose从入门到实战》第八章 Compose页面 导航

《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库文章来源地址https://www.toymoban.com/news/detail-729725.html

到了这里,关于《Jetpack Compose从入门到实战》第三章 定制 UI 视图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter实战·第二版-第三章 基础组件笔记

    第三章:基础组件 3.1文本及样式 3.1.1 Text 3.1.2 TextStyle 3.1.3 TextSpan 3.1.4 DefaultTextStyle 3.1.5字体 先将文字资源打包到应用,然后再pubspec.yaml中指定位置 根目录/assets(fonts) 使用字体 Package中的字体 lib/fonts/Raleway-Medium.ttf 3.2按钮 3.2.1 ElevatedButton 3.2.2 TextButton 3.2.3 OutlinedButton 3.2.4 IconB

    2024年02月12日
    浏览(54)
  • javacv从入门到精通——第三章:基本使用

    JavaCV的基本结构如下: JavaCV核心类 :JavaCV核心类是JavaCV库的核心,它包括了JavaCV的所有功能和特性,可以用来进行计算机视觉和人工智能任务的开发和实现。JavaCV核心类的主要功能包括:视频捕获、视频编解码、图像处理、人脸检测、特征提取等。 基本数据类型: JavaCV库支

    2023年04月16日
    浏览(51)
  • 《Opencv3编程入门》学习笔记—第三章

    记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。 一、图像的载入、显示和输出到文件 (一)OpenCV的命名空间 简单的OpenCV程序标配: (二)Mat类简析 表示从指定路径下把名为dota.jpg的图像载入到Mat类型的srcImage 变量中。 (三)图像的载入与显示概述

    2024年02月08日
    浏览(53)
  • 微信小程序开发实战课后习题解答————第三章(作业版)

    一、填空题 1、微信小程序中用    navigationBar      组件可以实现导航栏 2、 微信小程序中能够实现轮播效果的组件是    swiper    3、 微信小程序中实现滚动条事件的绑定方法是    bindscroll   4、 微信小程序中引入音频的组件是   InnerAudioContext   5、 微信小程序中控

    2024年02月09日
    浏览(53)
  • 开源数据库MYSQL DBA运维实战 第三章 备份

    丢/删 1.数据的一致性 2.服务的可用性 3.1物理备份/冷备份 直接复制数据库文件,适用于大型数据库环境,不受存储引擎的限制,但不能恢复到不同的mysql tar,cp,scp 拷贝数据,有点快,缺点服务停止 3.2逻辑备份/热备份 备份的是建表,建库,插入等操作所执行SQL语句(DDL,DML,D

    2024年02月21日
    浏览(98)
  • 【UnityShader入门精要学习笔记】第三章(1)Unity Shader介绍

    本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 + 个人批注 项目源码 一堆新手会犯的错误 潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 从本章节开始我们要学习Shader相关的知识了,诸位看客可能有的

    2024年02月02日
    浏览(65)
  • 数据库SQL语言实战(五)(数据库系统概念第三章练习题)

    目录 前言知识 一、 关系模式 二、 属性域 例子 介绍 作用 三、Select常数 举例 解释  四、集合差运算 本质 举例  结论 练习题 3.17 3.18  3.21  总结  注:本文的SQL语言适用的是 Oracle数据库 与mySQL可能存在略微不同 模式的定义 :模式则是指数据库中 所有关系模式 的集合,它

    2024年04月22日
    浏览(59)
  • 【UnityShader入门精要学习笔记】第三章(2)Unity Shader的形式,章节答疑

    本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 + 个人批注 项目源码 一堆新手会犯的错误 潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 (该系列笔记中大多数都会复习前文的知识,特别是前文知识非

    2024年02月02日
    浏览(50)
  • 「第三章」python-docx 添加标题,word标题从入门到精通

    💡 1. add_heading() 简介 💡 2. add_heading() 基本用法 💡 3. 设置不同级别的标题 💡 4. 设置带有特殊字符的标题 💡 5. 使用循环添加多个标题 💡 6. 使用不同样式添加标题 💡 7. 结合其他元素使用标题 💡 8. 为标题设置复杂多变的样式 最近一段时间,一直在更新python关于PDF文档、

    2024年02月02日
    浏览(41)
  • Spark大数据分析与实战笔记(第三章 Spark RDD 弹性分布式数据集-02)

    人生很长,不必慌张。你未长大,我要担当。 传统的MapReduce虽然具有自动容错、平衡负载和可拓展性的优点,但是其最大缺点是采用非循环式的数据流模型,使得在迭代计算式要进行大量的磁盘IO操作。Spark中的RDD可以很好的解决这一缺点。 RDD是Spark提供的最重要的抽象概念

    2024年02月22日
    浏览(82)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包