This article is simultaneously published on my wechat official account. You can follow it by searching OpenCV or Android on wechat.

preface

The third week of the challenge is a speed competition. The winner is the one who completes the fastest according to the official design drawing and meets all design specifications. Not only do it fast, but also do it well, and the prize will not be less. The prize for this issue: Google Pixel 5. Know dry but industry bigwigs, spend a half a day pure when practice to complete the topic.

The design

Design style

Interface navigation

Interface annotation

Complete design: github.com/android/and…

knowledge

  • Theme: Custom theme
  • List: LazyColumn, LazyRow
  • Text: text input box, stylized text, custom font
  • Navigation: basic use, bottom navigation bar integration

The key to realize

Custom theme

Use theme elements to configure color, Shape, typography and other content in the interface layout. LocalImages and localElevations are user-defined.

@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
}
Copy the code
@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")}Copy the code

Stylize text

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
    )
)
Copy the code
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
        )
    }
}
Copy the code

Border password text input

TextField(
    modifier = Modifier
        .height(56.dp)
        .fillMaxWidth()
        .border(  // Set the 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(), // In password form
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password) // Password secure keyboard
)
Copy the code

Bottom navigation bar

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(a) {
    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()
                valcurrentRoute = 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() }
        }
    }
}
Copy the code

The effect

Welcome

Login

Home

The source code

Github.com/onlyloveyd/…