Compose Weekly #3:Bloom

onlyloveyd
• 阅读 1665

本文同步发表于我的微信公众号,在微信搜索 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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
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:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
onlyloveyd onlyloveyd
3年前
Android抖音去水印APP
本文同步发表于我的微信公众号,在微信搜索OpenCVorAndroid即可关注。前言微信8.0.0更新以后,大伙玩得不亦乐乎,除了会动的表情,特效的炸弹、烟花等,还有一个亮点就是微信个人状态背景,既可以挂图片,更可以挂视频,给人一种万物皆可短视频的感觉。我也很爱这个功能,但是奈何鄙人才疏学浅,没法制作炫酷的短视频。只能使用去抖音水印工具获取
onlyloveyd onlyloveyd
3年前
协变和逆变
本文同步发表于我的微信公众号,在微信搜索OpenCVorAndroid即可关注。协变、逆变概念许多程序设计语言的类型系统支持子类型。例如,如果Cat是Animal的子类型,那么Cat类型的表达式可用于任何出现Animal类型表达式的地方。所谓的变型(variance)是指如何根据组成类型之间的子类型关系,来确定更复杂的类型之间(例如C
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
onlyloveyd onlyloveyd
3年前
Compose Weekly #2:Countdown Timer
本文同步发表于我的微信公众号,在微信搜索OpenCVorAndroid即可关注。前言最近Android官方发起了JetpackCompose的推广活动:JetpackCompose开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用JetpackCompose技术结题后按要求提交,即可参与活动。
onlyloveyd onlyloveyd
3年前
Compose Weekly #1: 小狗领养应用
本文同步发表于我的微信公众号,在微信搜索OpenCVorAndroid即可关注。前言最近Android官方发起了JetpackCompose的推广活动:JetpackCompose开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用JetpackCompose技术结题后按要求提交,即可参与活动。
onlyloveyd onlyloveyd
3年前
Compose Weekly #4:Weather App
本文同步发表于我的微信公众号,在微信搜索OpenCVorAndroid即可关注。前言It'sraining...Compose!Pulloutallthestopsforthisfinalchallenge.BuildabeautifulweatherappforachancetowinaPixel
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究