Compose Weekly #3:Bloom

onlyloveyd
• 阅读 1213

本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。

前言

第三周挑战赛是速度比拼,按照官方发出的设计图最快完成且符合所有设计规范者胜出。不仅要做得快,还要做得好,奖品自然不会少。这一期的奖品是:Google Pixel 5。深知干不过业界大佬们,花个半天纯当练手完成题目。

设计图

设计风格

Compose Weekly #3:Bloom

界面导航

Compose Weekly #3:Bloom

界面标注

Compose Weekly #3:Bloom

完整设计图:https://github.com/android/android-dev-challenge-compose/blob/assets/Bloom.zip

知识点

  • 主题:自定义主题
  • 列表:LazyColumn、LazyRow
  • 文字:文本输入框、风格化文本、自定义字体
  • 导航:基础使用、底部导航栏集成

关键实现

定义主题

界面布局中使用主题元素配置color、shape、typography等内容。localImages、localElevations为自定义内容。

@Composable
fun BloomTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }
    val images = if (darkTheme) DarkImages else LightImages
    val elevations = AllElevations

    CompositionLocalProvider(
        localImages provides images,
        localElevations provides elevations
    ) {
        MaterialTheme(
            colors = colors,
            typography = typography,
            shapes = shapes,
            content = content
        )
    }
}

object BloomTheme {
    val colors: Colors
        @Composable
        get() = MaterialTheme.colors

    val typography: Typography
        @Composable
        get() = MaterialTheme.typography

    val shapes: Shapes
        @Composable
        get() = MaterialTheme.shapes

    val images: Images
        @Composable
        get() = localImages.current

    val elevations: Elevations
        @Composable
        get() = localElevations.current
}
@Immutable
data class Images(
    @DrawableRes val welcomeBackground: Int,
    @DrawableRes val welcomeIllos: Int,
    @DrawableRes val welcomeLogo: Int
)

internal val localImages = staticCompositionLocalOf<Images> {
    error("No LocalImages specified")
}

风格化文本

val termsString = buildTermsString(
    stringResource(R.string.login_terms),
    listOf(
        stringResource(R.string.terms),
        stringResource(R.string.privancy)
    )
)
Text(
    text = termsString,
    textAlign = TextAlign.Center,
    modifier = Modifier.paddingFromBaseline(
        top = 24.dp,
        bottom = 16.dp
    )
)
fun buildTermsString(source: String, segments: List<String>) = buildAnnotatedString {
    append(source)
    for (segment in segments) {
        val startIndex = source.indexOf(segment)
        val endIndex = startIndex + segment.length
        addStyle(
            style = SpanStyle(textDecoration = TextDecoration.Underline),
            start = startIndex,
            end = endIndex
        )
    }
}

带边框密码文本输入

TextField(
    modifier = Modifier
        .height(56.dp)
        .fillMaxWidth()
        .border(  // 设置边框
            width = 1.dp,
            color = Color(0xFF9E9E9E),
            shape = BloomTheme.shapes.small
        ),
    value = password,
    onValueChange = { password = it },
    singleLine = true,
    placeholder = {
        Text(
            text = stringResource(R.string.password_hint),
            style = BloomTheme.typography.body1,
        )
    },
    textStyle = BloomTheme.typography.body1,
    colors = TextFieldDefaults.textFieldColors(
        backgroundColor = Color.Transparent,
        textColor = BloomTheme.colors.onPrimary
    ),
    visualTransformation = PasswordVisualTransformation(), // 密码形式
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password) // 密码安全键盘
)

底部导航栏

sealed class Screen(
    val route: String,
    @StringRes val resourceId: Int,
    val icon: ImageVector
) {
    object Home : Screen("home", R.string.home, Icons.Filled.Home)
    object Favorites : Screen("favorite", R.string.favorites, Icons.Filled.FavoriteBorder)
    object Profile : Screen("profile", R.string.profile, Icons.Filled.AccountCircle)
    object Cart : Screen("cart", R.string.cart, Icons.Filled.ShoppingCart)
}

val items = listOf(
    Screen.Home,
    Screen.Favorites,
    Screen.Profile,
    Screen.Cart
)

@Composable
fun Main() {
    val navController = rememberNavController()

    Scaffold(
        bottomBar = {
            BottomNavigation(
                modifier = Modifier
                    .navigationBarsPadding()
                    .height(56.dp),
                backgroundColor = MaterialTheme.colors.primary,
                contentColor = MaterialTheme.colors.onPrimary,
                elevation = BloomTheme.elevations.bottomNavigation
            ) {
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentRoute = navBackStackEntry?.arguments?.getString(KEY_ROUTE)
                items.forEach { screen ->
                    BottomNavigationItem(
                        selected = currentRoute == screen.route,
                        onClick = {
                            navController.navigate(screen.route) {
                                popUpTo = navController.graph.startDestination
                                launchSingleTop = true
                            }
                        },
                        icon = {
                            Icon(
                                imageVector = screen.icon,
                                contentDescription = stringResource(id = screen.resourceId),
                                modifier = Modifier.size(24.dp, 24.dp),
                                tint = MaterialTheme.colors.onPrimary
                            )
                        },
                        label = {
                            Text(
                                stringResource(id = screen.resourceId),
                                style = MaterialTheme.typography.caption
                            )
                        }
                    )
                }
            }
        }
    ) {
        NavHost(navController, startDestination = Screen.Home.route) {
            composable(Screen.Home.route) { Home() }
            composable(Screen.Favorites.route) { Favorites() }
            composable(Screen.Profile.route) { Profile() }
            composable(Screen.Cart.route) { Cart() }
        }
    }
}

效果

Welcome

Compose Weekly #3:Bloom

Login

Compose Weekly #3:Bloom

Home

Compose Weekly #3:Bloom

源码

https://github.com/onlyloveyd/Jetpack-Compose-SpeedRound

点赞
收藏
评论区
推荐文章
刘望舒 刘望舒
1年前
Android AOSP基础(二)AOSP源码和内核源码下载
title: "Android AOSP基础(二)AOSP源码和内核源码下载"date: 201939 00:18cover: https://s2.ax1x.com/2019/05/27/VZRBi4.jpgtag: AOSP基础categories: Android框架层本文首发于微信公众号「后厂技术官」 前言这篇文章我们来学习如何下载AOSP 源码,
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录 问题 用navicat导入数据时,报错: 原因这是因为当前的MySQL不支持datetime为0的情况。 解决修改sql\mode: sql\mode:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
小森森 小森森
2个月前
校园表白墙微信小程序V1.0 SayLove -基于微信云开发-一键快速搭建,开箱即用
后续会继续更新,敬请期待2.0全新版本 欢迎添加左边的微信一起探讨!项目地址:](https://www.aliyun.com/activity/daily/bestoffer?userCodesskuuw5n) \2. Bug修复更新日历 2. 情侣脸功能大家不要使用了,现在阿里云的接口已经要收费了(土豪请随意), \ \ 和 注意
Wesley13 Wesley13
1年前
Oracle JDK7 bug 发现、分析与解决实战
> 本文首发于 vivo互联网技术 微信公众号 > 链接: [https://mp.weixin.qq.com/s/8f34CaTp--Wz5pTHKA0Xeg](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2F8f34CaTp--Wz5p
Stella981 Stella981
1年前
ASMSupport教程4.9 生成三元运算符
<p>这节我们介绍如何用ASMSupport生成三元运算符(... ? ... : ... )运算符。我们预计生成如下代码:</p> <div id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:935e30cc-3321-4e00-93ba-9834f3a4e044" class="wlWriterEditableS
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序 select * from table_name order id desc; 2.按照指定(多个)字段排序 select * from table_name order id desc,status desc; 3.按照指定字段和规则排序 selec
Stella981 Stella981
1年前
Android蓝牙连接汽车OBD设备
//设备连接 public class BluetoothConnect implements Runnable {     private static final UUID CONNECT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Stella981 Stella981
1年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“**Java进阶架构师**”,点击右上角,将我们设为**★**“**星标**”!这样才不会错过每日进阶架构文章呀。   ![](http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)   **2
3A网络 3A网络
2个月前
开发一个不需要重写成 Hive QL 的大数据 SQL 引擎
# 开发一个不需要重写成 Hive QL 的大数据 SQL 引擎 学习大数据技术的核心原理,掌握一些高效的思考和思维方式,构建自己的技术知识体系。明白了原理,有时甚至不需要学习,顺着原理就可以推导出各种实现细节。 各种知识表象看杂乱无章,若只是学习
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞 # 背景 在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
3A网络 3A网络
2个月前
理解 virt、res、shr 之间的关系(linux 系统篇)
# 理解 virt、res、shr 之间的关系(linux 系统篇) **前言** 想必在 linux 上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题 —— 你的程序在运行时占用了多少内存(物理内存)? 通常我们可以通过 t