Flutter in a Weekend: Sunday — Detail View creation

In the first two steps of this blog post series, we covered how to install Flutter to our system and how can we create views with the information that we retrieved from the server.

Now it is time for us to continue with the last part: Detail View creation and code cleanup.

Right now application only shows the name of the movie and the poster of it. But we are holding more information in our Movie object than these two. Let’s pass these information to a new view and use it.

Creating Detail View and Navigating to it

For keeping everything more clear and independent from each other, let’s create a new Dart file called MovieDetail.dart.

After we create the file, we will create our class as StatelessWidget. We will also create a variable for the current movie object and we will pass this object to our detail page by passing it in a constructor.

class MovieDetail extends StatelessWidget {
    // Movie object to handle.
Movie movie;
// Constructor for the class.
MovieDetail(this.movie);
    @override
Widget build(BuildContext context) {
// View creation will be here.
}
}

Now that everything is settled, let’s create the build method. Let’s start with the app bar. Let’s put movie title there.

...
@override
Widget build(BuildContext context) {
         return new Scaffold(
appBar: new AppBar(
title: new Text(movie.title),
)
);
}

For the rest of the view, we need to continue from the body keyword. We will use a ListView for that purpose. ListView is a view that creates a scrollable, linear array of widgets from an explicit list. First, we will add an item to the backdrop image.

...
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(movie.title),
),
body: new ListView(
children: <Widget>[
new Image.network(
"https://image.tmdb.org/t/p/w500/" + movie.backdropPath)
]
)
);
}

Second item will be a Container for the movie title, release data and rating. Container is a widget can be used to position the children widgets. For the horizontal positioning, we use Row and for the vertical positioning, we use Column attribute of Container.

We will position the title and release date in the same column and position the rating right to it with a star icon.

...
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(movie.title),
),
body: new ListView(
children: <Widget>[
new Image.network(
"https://image.tmdb.org/t/p/w500/" + movie.backdropPath),
new Container(
padding: const EdgeInsets.all(32.0),
child: new Row(
children: [
// First child in the Row for the name and the
// Release date information.
new Expanded(
// Name and Release date are in the same column
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Code to create the view for name.
new Container(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Text(
"Original Name: " + movie.originalTitle,
style: new TextStyle(
fontWeight: FontWeight.bold,
),
),
),
// Code to create the view for release date.
new Text(
"Release Date: " + movie.releaseDate,
style: new TextStyle(
color: Colors.grey[500],
),
),
],
),
),
// Icon to indicate the rating.
new Icon(
Icons.star,
color: Colors.red[500],
),
new Text('${movie.voteAverage}'),
],
),
)
]
)
);
}
...

Now it is time to add the overview of the movie as the last element .

...
@override
Widget build(BuildContext context) {
...
new Container(
padding: const EdgeInsets.all(32.0),
child: new Text(movie.overview,
softWrap: true,
)
)
...
}

Now we will continue with our last operation. We will navigate from our main page to the detail page. In the main.dart file there is a TODO from yesterday. We will add a code to navigate to the detail screen. We will be using a special class called Navigator. It is a widget that stacks the history of child widgets and uses it for navigating between it. When we push a new widget to the stack, it goes to the top and becomes visible to the user and when we go back, it pops it and returns the other available widget.

We will be also using a new attribute called Route. A route is an interface between the widgets in the navigator stack and it is responsible for transition between those. We will be using something calledMaterialPageRoute which is a route special version of Route for the Material applications.

Let’s add the code below instead of the TODO mentioned above to create the animation behaviour.

Navigator.push(context, new MaterialPageRoute(builder:
(BuildContext context) => new MovieDetail(movie)));

Now when you click on the list elements, you can see that it opens up the detail view with the related information.

Last Cleanup

We achieved what we wanted to achieve but before we say goodbye to each other, I want to do one more thing :) Since we have a dart file dedicated to Movie detail, why don’t we create one for Movie list too?

Let’s create it and move the related information into it.

class MovieList extends StatelessWidget { 
// Code will be here
}

Let’s ignore the error on MovieList for now, because it wants us to create a widget and we will do it the last. We will start by moving getMovies , createMovieList and createMovieCardItem methods. Afterwards, it will want us to import the missing parts and we will do it. Now it is time for creating the widget.

Let’s add build method to our widget.

@override
Widget build(BuildContext context) {
// TODO: implement build
}

We will create the widget by moving the code in the body part of the Scaffold in main method to the build method above.

@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: getMovies(),
builder: (BuildContext context,
AsyncSnapshot<List> snapshot) {
if (!snapshot.hasData)
// Shows progress indicator until the data is load.
return new MaterialApp(
home: new Scaffold(
body: new Center(
child: new CircularProgressIndicator(),
),
)
);
// Shows the real data with the data retrieved.
List movies = snapshot.data;
return new CustomScrollView(
primary: false,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.all(10.0),
sliver: new SliverGrid.count(
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
crossAxisCount: 2,
children: createMovieCardItem(movies, context),
),
),
],
);
}
);
}

Now we will call our new widget in the main.dart file and we will be ready.

// Main method starts execution
void main() {
runApp(
new MaterialApp(
home: new Scaffold(
// App toolbar code
appBar: new AppBar(
title: new Text('Movie List'),
),
body: new MovieList()
)
)
);
}

It looks better, isn’t it?

Conclusion

Good job! We have covered plenty of concepts and made an awesome application for Android and iOS.

iOS
Android

We have covered plenty of new concepts about Flutter. But this was just the beginning, there is a whole world behind it and as I told in the very beginning, the best way to learn something is to work with it. You should keep discovering Flutter and share your experiences.

Thank you for reading, if you have any comments feel free to send it and if you like it do not forget to clap the post. Goodbye!

p.s. Here is the GitHub project.