Initial Movies UI
Flesh out the screens
Now we flesh out the screens, making a very simple (but inefficient) list, and a simple display.
Our MovieDisplay
sets up a Column
as the main content of the Scaffold
. Note
the paddingValues
that are passed to the content lambda. These define the padding you must use
to avoid overlapping with other slots in the Scaffold
.
show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieDisplay.kt
// ...
@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieDisplayUi(
// ...
) {
Scaffold(
// ...
modifier = modifier,
) { innerPadding ->
// Text(
// text = "Movie Display: ${movie.title}",
// modifier = Modifier.padding(innerPadding),
// )
Column (
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
Label (textId = R.string.title)
Display(text = movie.title)
Label(textId = R.string.description)
Display(text = movie.description)
}
}
}
Our Column
is scrollable and stacks Label
s and Display
s to show the details
of a movie. (Be sure to use our Label
instead of the Material3 Label
)
MovieListUi
is a bit more complex. It uses a Scaffold
in the same way as MovieDisplay
,
but the contents of its column are dynamic. We iterate through the list of movies
using forEach
, and create a nice little Card
for each movie, showing an icon and title.
show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
// ...
@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieListUi(
// ...
) {
Scaffold(
// ...
modifier = modifier,
) { innerPadding ->
// Text(
// text = "Movie List",
Column (
modifier = Modifier
.padding(innerPadding)
// .clickable {
// onMovieClicked(movies[0])
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
movies.forEach { movie ->
Card (
elevation = CardDefaults.cardElevation(
defaultElevation = 8.dp,
),
onClick = {
onMovieClicked(movie)
},
modifier = Modifier.padding(8.dp)
) {
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(8.dp)
) {
Icon(
imageVector = Icons.Default.Star,
contentDescription = stringResource(id = R.string.movie)
)
Display(text = movie.title)
}
}
}
}
// )
}
}
We make the icon and title line up nicely by adding an alignment specification.
By defining onClick
at the Card
level,
show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
// ...
@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieListUi(
// ...
) {
Scaffold(
// ...
) { innerPadding ->
// ...
Column (
// ...
) {
movies.forEach { movie ->
Card (
// ...
defaultElevation = 8.dp,
),
onClick = {
onMovieClicked(movie)
},
modifier = Modifier.padding(8.dp)
) {
// ...
}
}
}
// ...
}
}
the user can click anywhere inside the card to select the movie. That click passes the
movie for that card to onMovieClicked()
, informing the caller that a movie has been
selected.
As usual, define any literal strings that the user will see in
app/src/main/res/values/strings.xml
.
All code changes
CHANGED: app/src/main/java/com/androidbyexample/compose/movies/MainActivity.kt
package com.androidbyexample.compose.movies
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.androidbyexample.compose.movies.screens.Ui
import com.androidbyexample.compose.movies.ui.theme.MoviesTheme
class MainActivity : ComponentActivity() {
private val viewModel by viewModels<MovieViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MoviesTheme {
Ui(
viewModel = viewModel,
) {
finish()
}
}
}
}
}
CHANGED: app/src/main/java/com/androidbyexample/compose/movies/screens/MovieDisplay.kt
package com.androidbyexample.compose.movies.screens
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.androidbyexample.compose.movies.Movie
import com.androidbyexample.compose.movies.R
import com.androidbyexample.compose.movies.components.Display
import com.androidbyexample.compose.movies.components.Label
@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieDisplayUi(
movie: Movie,
modifier: Modifier = Modifier,
) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = movie.title)
}
)
},
modifier = modifier,
) { innerPadding ->
// Text(
// text = "Movie Display: ${movie.title}",
// modifier = Modifier.padding(innerPadding),
// )
Column (
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
Label (textId = R.string.title)
Display(text = movie.title)
Label(textId = R.string.description)
Display(text = movie.description)
}
}
}
CHANGED: app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
package com.androidbyexample.compose.movies.screens
//import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.androidbyexample.compose.movies.Movie
import com.androidbyexample.compose.movies.R
import com.androidbyexample.compose.movies.components.Display
@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieListUi(
movies: List<Movie>,
modifier: Modifier = Modifier,
onMovieClicked: (Movie) -> Unit,
) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = stringResource(R.string.movies))
}
)
},
modifier = modifier,
) { innerPadding ->
// Text(
// text = "Movie List",
Column (
modifier = Modifier
.padding(innerPadding)
// .clickable {
// onMovieClicked(movies[0])
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
movies.forEach { movie ->
Card (
elevation = CardDefaults.cardElevation(
defaultElevation = 8.dp,
),
onClick = {
onMovieClicked(movie)
},
modifier = Modifier.padding(8.dp)
) {
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(8.dp)
) {
Icon(
imageVector = Icons.Default.Star,
contentDescription = stringResource(id = R.string.movie)
)
Display(text = movie.title)
}
}
}
}
// )
}
}
CHANGED: app/src/main/res/values/strings.xml
<resources>
<string name="app_name">Movies</string>
<string name="movies">Movies</string>
<string name="title">Title</string>
<string name="description">Description</string>
<string name="movie">Movie</string>
</resources>