For offline viewing, get the eBook (PDF & ePUB) version + source code here.
Open activity_movie_details.xml and let’s build our UI.
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/movie_backdrop"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@+id/backdrop_guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/movie_poster_card"
android:layout_width="128dp"
android:layout_height="172dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
app:cardCornerRadius="4dp"
app:layout_constraintBottom_toBottomOf="@+id/backdrop_guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/backdrop_guideline">
<ImageView
android:id="@+id/movie_poster"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/backdrop_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.4" />
<TextView
android:id="@+id/movie_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/movie_poster_card"
app:layout_constraintTop_toBottomOf="@+id/backdrop_guideline" />
<TextView
android:id="@+id/movie_release_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#757575"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="@+id/movie_title"
app:layout_constraintTop_toBottomOf="@+id/movie_title" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/movie_poster_title_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="movie_rating,movie_release_date" />
<TextView
android:id="@+id/movie_overview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/movie_poster_title_barrier" />
<RatingBar
android:id="@+id/movie_rating"
style="@style/Widget.AppCompat.RatingBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="@+id/movie_poster_card"
app:layout_constraintStart_toStartOf="@+id/movie_poster_card"
app:layout_constraintTop_toBottomOf="@+id/movie_poster_card" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
Open your MovieDetailsActivity and instantiate the views.
class MovieDetailsActivity : AppCompatActivity() {
private lateinit var backdrop: ImageView
private lateinit var poster: ImageView
private lateinit var title: TextView
private lateinit var rating: RatingBar
private lateinit var releaseDate: TextView
private lateinit var overview: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie_details)
backdrop = findViewById(R.id.movie_backdrop)
poster = findViewById(R.id.movie_poster)
title = findViewById(R.id.movie_title)
rating = findViewById(R.id.movie_rating)
releaseDate = findViewById(R.id.movie_release_date)
overview = findViewById(R.id.movie_overview)
}
}
Just above the class name, add your intent variables.
const val MOVIE_BACKDROP = "extra_movie_backdrop"
const val MOVIE_POSTER = "extra_movie_poster"
const val MOVIE_TITLE = "extra_movie_title"
const val MOVIE_RATING = "extra_movie_rating"
const val MOVIE_RELEASE_DATE = "extra_movie_release_date"
const val MOVIE_OVERVIEW = "extra_movie_overview"
class MovieDetailsActivity : AppCompatActivity() { ... }
These variables will be used as keys when we pass intent extras to MovieDetailsActivity.
Use the keys above to populate the movie’s details.
class MovieDetailsActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
val extras = intent.extras
if (extras != null) {
populateDetails(extras)
} else {
finish()
}
}
private fun populateDetails(extras: Bundle) {
extras.getString(MOVIE_BACKDROP)?.let { backdropPath ->
Glide.with(this)
.load("https://image.tmdb.org/t/p/w1280$backdropPath")
.transform(CenterCrop())
.into(backdrop)
}
extras.getString(MOVIE_POSTER)?.let { posterPath ->
Glide.with(this)
.load("https://image.tmdb.org/t/p/w342$posterPath")
.transform(CenterCrop())
.into(poster)
}
title.text = extras.getString(MOVIE_TITLE, "")
rating.rating = extras.getFloat(MOVIE_RATING, 0f) / 2
releaseDate.text = extras.getString(MOVIE_RELEASE_DATE, "")
overview.text = extras.getString(MOVIE_OVERVIEW, "")
}
}
The available backdrop sizes are:
Open your MainActivity and create a new method called showMovieDetails()
.
class MainActivity : AppCompatActivity() {
...
private fun showMovieDetails(movie: Movie) {
val intent = Intent(this, MovieDetailsActivity::class.java)
intent.putExtra(MOVIE_BACKDROP, movie.backdropPath)
intent.putExtra(MOVIE_POSTER, movie.posterPath)
intent.putExtra(MOVIE_TITLE, movie.title)
intent.putExtra(MOVIE_RATING, movie.rating)
intent.putExtra(MOVIE_RELEASE_DATE, movie.releaseDate)
intent.putExtra(MOVIE_OVERVIEW, movie.overview)
startActivity(intent)
}
...
}
Open your MoviesAdapter and add a new parameter in the constructor which is a higher-order function that will be called when a movie is clicked.
class MoviesAdapter(
private var movies: MutableList<Movie>,
private val onMovieClick: (movie: Movie) -> Unit
) : ...
Invoke onMovieClick
when a movie is clicked.
class MoviesAdapter(
private var movies: MutableList<Movie>,
private val onMovieClick: (movie: Movie) -> Unit
) : RecyclerView.Adapter<MoviesAdapter.MovieViewHolder>() {
...
inner class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
...
fun bind(movie: Movie) {
...
itemView.setOnClickListener { onMovieClick.invoke(movie) }
}
}
}
Open your MainActivity and pass a higher-order function to your adapters which calls the showMovieDetails()
method that you’ve just created.
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
popularMoviesAdapter = MoviesAdapter(mutableListOf()) { movie -> showMovieDetails(movie) }
...
...
topRatedMoviesAdapter = MoviesAdapter(mutableListOf()) { movie -> showMovieDetails(movie) }
...
...
upcomingMoviesAdapter = MoviesAdapter(mutableListOf()) { movie -> showMovieDetails(movie) }
...
}
...
}
Run the app, tap any movie and you should see something like this:
Congratulations! You have just made a full-blown and portfolio-worthy Android app that you can put on Google Play Store.
In the next chapter, we’ll explore some feature ideas that you can do next to even improve this version. Head over to Part 6 - What’s Next?
Do You Want to Become Really Good at Android Development?
Here are 7 ways to do it👇