Create Composables with Jetpack Compose

Sep 10 2024 · Kotlin 1.9, Android 14, Android Studio Jellyfish | 2023.3.1

Lesson 06: Use Material Design

Demo

Episode complete

Play next episode

Next
Transcript

Open the Starter project in the 06-use-material-design directory of the m3-cjp-materials repo, in Android Studio Koala or later.

Wait for the project to build.

This is the same project you have worked on so far. In this demo, you’ll create a custom theme for your app.

If you expand the res directory, you’ll notice two fonts in the font directory. These are the fonts you’ll use to create a custom-type scale.

First, create a ui.theme package in the root app package. Next, create a file named Color.kt in the same package. This will host your color palette. Add  the following code to the file:

import androidx.compose.ui.graphics.Color  
  
val colorPrimary = Color(0xFF006837)  
val colorPrimaryDark = Color(0xFF004012)  
val colorAccent = Color(0xFFc75f00)

These colors represent the Kodeco brand palette.

Next, create a new file in the ui.theme package, and name it Type.kt. Enter the following into the file:

import androidx.compose.material.Typography  
import androidx.compose.ui.text.TextStyle  
import androidx.compose.ui.text.font.Font  
import androidx.compose.ui.text.font.FontFamily  
import androidx.compose.ui.text.font.FontWeight  
import androidx.compose.ui.text.style.TextAlign  
import androidx.compose.ui.unit.sp  
import com.yourcompany.android.githubusers.R  
  
val rubik = FontFamily(  
  Font(R.font.rubik_regular, FontWeight.Normal),  
)  
  
val chivo = FontFamily(  
  Font(R.font.chivo_bold, FontWeight.Bold)  
)  
  
val Typography = Typography(  
  h3 = TextStyle(  
    fontSize = 36.sp,  
    fontFamily = rubik,  
    fontWeight = FontWeight.ExtraBold,  
    letterSpacing = (-8).sp  
  ),  
  
  h4 = TextStyle(  
    fontSize = 24.sp,  
    fontFamily = rubik,  
    fontWeight = FontWeight.ExtraBold,  
    letterSpacing = (-8).sp  
  ),  
  
  h5 = TextStyle(  
    fontSize = 24.sp,  
    fontFamily = chivo,  
    fontWeight = FontWeight.Bold  
  ),  
  
  h6 = TextStyle(  
    fontSize = 16.sp,  
    fontFamily = chivo,  
    fontWeight = FontWeight.Bold  
  ),  
  
  subtitle1 = TextStyle(  
    fontSize = 16.sp,  
    fontFamily = chivo,  
    fontWeight = FontWeight.Normal  
  ),  
  
  subtitle2 = TextStyle(  
    fontSize = 14.sp,  
    fontFamily = chivo,  
    fontWeight = FontWeight.Bold  
  ),  
  
  body2 = TextStyle(  
    fontSize = 14.sp,  
    fontFamily = rubik,  
    fontWeight = FontWeight.Normal,  
    lineHeight = 22.sp  
  ),  
  
  button = TextStyle(  
    fontSize = 14.sp,  
    fontFamily = rubik,  
    fontWeight = FontWeight.Normal  
  ),  
  
  overline = TextStyle(  
    fontSize = 14.sp,  
    fontFamily = rubik,  
    fontWeight = FontWeight.Bold,  
    textAlign = TextAlign.Center,  
    letterSpacing = (3).sp  
  )  
)

Here, you’re using the two fonts to create a custom type scale. The components of the app will use this.

Next, create a Shape.kt file in the same package and enter the following:

import androidx.compose.foundation.shape.RoundedCornerShape  
import androidx.compose.material.Shapes  
import androidx.compose.ui.unit.dp  
  
val Shapes = Shapes(  
  small = RoundedCornerShape(4.dp),  
  medium = RoundedCornerShape(8.dp),  
  large = RoundedCornerShape(16.dp)  
)

Here, you created a shape definition to be used by the app.

Finally, you’ll tie it all together in a custom theme.

In the same package, create a new file called Theme.kt and enter the following:

import androidx.compose.material.darkColors  
import androidx.compose.material.lightColors  
  
private val DarkColorPalette = darkColors(  
  primary = colorPrimaryDark,  
  primaryVariant = colorPrimary,  
  secondary = colorAccent  
)  
  
private val LightColorPalette = lightColors(  
  primary = colorPrimary,  
  primaryVariant = colorPrimaryDark,  
  secondary = colorAccent  
)  

Here, you created a dark and light mode palette using your color definitions. Next, add the following to the file:

@Composable  
fun GithubUserAppTheme(  
  darkTheme: Boolean = isSystemInDarkTheme(),  
  content: @Composable () -> Unit  
) {  
  val colors = if (darkTheme) {  
    DarkColorPalette  
  } else {  
    LightColorPalette  
  }  
  
  MaterialTheme(  
    colors = colors,  
    typography = Typography,  
    shapes = Shapes,  
    content = content  
  )  
}

Here, you’ve defined a new GithubUserAppTheme that uses the color types and shape definition you created earlier. isSystemInDarkTheme() is a Composable that informs you whether the system is using a dark theme or not. Based on the returned value, you choose between the light and dark color palettes.

First, modify the GitHubRepoCard Composable to use the shapes and types.

For the wrapping Card, use the shape as follows:

Card(shape = MaterialTheme.shapes.large)

Next, apply the typographic scales to the Text components. Change the repo name text composable to use h5:

Text(  
  text = repo.name,  
  style = MaterialTheme.typography.h5,  
)

Next, change the description to use body1:

Text(  
  text = it,  
  style = MaterialTheme.typography.body1  
)

Finally, change the URL text to use the subtitle text style, and secondary color:

Text(  
  text = repo.htmlUrl,  
  style = MaterialTheme.typography.subtitle2,  
  color = MaterialTheme.colors.secondary,  
  textDecoration = TextDecoration.Underline  
)

To see the theme in action, wrap your preview composable with the theme, as follows:

@Preview(uiMode = UI_MODE_NIGHT_YES)  
@Preview(uiMode = UI_MODE_NIGHT_NO)  
@Composable  
fun PreviewGitHubRepoCard() {  
  GithubUserAppTheme {  
    GitHubRepoCard(  
        /*...*/
    
    )  
  }  
}

Finally, to use the theme in the entire app, apply it on the setContent block and wrap your GitHubRepoList composable.

setContent {  
  GithubUserAppTheme {  
    val state by viewModel.state.observeAsState()
    Column(modifier = Modifier.padding(16.dp)) {
      state?.forEach { repo ->
        GitHubRepoCard(repo)
        Spacer(modifier = Modifier.height(16.dp))
      }
    }
  }
}

That concludes this demo. Continue with the lesson for a summary.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion