Update location: first in the public account, the next day update in nuggets, Sifu, developer headlines and other places;
More communication: You can add me on wechat at 372623326 and follow me on Weibo at CoderWhy
Code address: github.com/coderwhy/fl…
Due to Mac scheduling issues (Mac is busy with other things earlier), here is a periodic exercise I wrote.
Due to the time problem, each step is not explained in detail. I hope to update a video to explain it to you later.
I. Data request and transformation
1.1. Simple encapsulation of network requests
At present, I haven’t explained the knowledge related to network request in detail. In the development, we will choose more local DIO.
I’ll go into more detail about several ways to make network requests later, but HERE I’ve wrapped a simple tool based on DIO:
Dart configuration file: http_config.dart
const baseURL = "http://123.207.32.32:8000";
const timeout = 5000;
Copy the code
The network request tool file: http_request.dart
- This is just a method package for now, more details will be added later
import 'package:dio/dio.dart';
import 'http_config.dart';
class HttpRequest {
// 1. Create instance objects
static BaseOptions baseOptions = BaseOptions(connectTimeout: timeout);
static Dio dio = Dio(baseOptions);
static Future<T> request<T>(String url, {String method = "get".Map<String.dynamic> params}) async {
// 1. Separate related Settings
Options options = Options();
options.method = method;
2. Send a network request
try {
Response response = await dio.request<T>(url, queryParameters: params, options: options);
return response.data;
} on DioError catch (e) {
throwe; }}}Copy the code
1.2. Conversion of home page data request
Douban data acquisition
Here I use douban API interface to request data:
- Douban.uieee.com/v2/movie/to…
Encapsulation of model objects
In object-oriented development, data requests are not used directly as front-end, but encapsulated as model objects:
- It’s easy for front-end developers not to think object-oriented or typologically.
- But the current move toward TypeScript is helping to reinforce this way of thinking.
In order to facilitate the future use of the requested data, I divided the data into the following model:
Person, Actor, Director models: These are used in the MovieItem
class Person {
String name;
String avatarURL;
Person.fromMap(Map<String.dynamic> json) {
this.name = json["name"];
this.avatarURL = json["avatars"] ["medium"]; }}class Actor extends Person {
Actor.fromMap(Map<String.dynamic> json): super.fromMap(json);
}
class Director extends Person {
Director.fromMap(Map<String.dynamic> json): super.fromMap(json);
}
Copy the code
MovieItem model:
int counter = 1;
class MovieItem {
int rank;
String imageURL;
String title;
String playDate;
double rating;
List<String> genres;
List<Actor> casts;
Director director;
String originalTitle;
MovieItem.fromMap(Map<String.dynamic> json) {
this.rank = counter++;
this.imageURL = json["images"] ["medium"];
this.title = json["title"];
this.playDate = json["year"];
this.rating = json["rating"] ["average"];
this.genres = json["genres"].cast<String> ();this.casts = (json["casts"] as List<dynamic>).map((item) {
return Actor.fromMap(item);
}).toList();
this.director = Director.fromMap(json["directors"] [0]);
this.originalTitle = json["original_title"]; }}Copy the code
Home page data request encapsulation and model transformation
Here I encapsulate a special class for requesting the home page data to make our request code more formally managed: HomeRequest
- Currently there is only one method getMovieTopList in the class;
- Subsequent requests for other home page data continue to encapsulate the requested methods here;
import 'package:douban_app/models/home_model.dart';
import 'http_request.dart';
class HomeRequest {
Future<List<MovieItem>> getMovieTopList(int start, int count) async {
// 1. Concatenate URL
final url = "https://douban.uieee.com/v2/movie/top250?start=$start&count=$count";
// 2. Send request
final result = await HttpRequest.request(url);
// 3. Convert to model objects
final subjects = result["subjects"];
List<MovieItem> movies = [];
for (var sub in subjects) {
movies.add(MovieItem.fromMap(sub));
}
returnmovies; }}Copy the code
Request the data in the home.dart file
2. Interface effect realization
2.1. The overall code of the home page
The overall layout of the home page is very simple, using a ListView
import 'package:douban_app/models/home_model.dart';
import 'package:douban_app/network/home_request.dart';
import 'package:douban_app/views/home/childCpns/movie_list_item.dart';
import 'package:flutter/material.dart';
const COUNT = 20;
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home page"), ), body: Center( child: HomeContent(), ), ); }}class HomeContent extends StatefulWidget {
@override
_HomeContentState createState() => _HomeContentState();
}
class _HomeContentState extends State<HomeContent> {
// Initializes the network request object on the home page
HomeRequest homeRequest = HomeRequest();
int _start = 0;
List<MovieItem> movies = [];
@override
void initState() {
super.initState();
// Request movie list data
getMovieTopList(_start, COUNT);
}
void getMovieTopList(start, count) {
homeRequest.getMovieTopList(start, count).then((result) {
setState(() {
movies.addAll(result);
});
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: movies.length,
itemBuilder: (BuildContext context, int index) {
returnMovieListItem(movies[index]); }); }}Copy the code
2.2. Individual Item parts
The following is an analysis of the interface structure:
We can implement the code according to the corresponding structure:
import 'package:douban_app/components/dash_line.dart';
import 'package:flutter/material.dart';
import 'package:douban_app/models/home_model.dart';
import 'package:douban_app/components/star_rating.dart';
class MovieListItem extends StatelessWidget {
final MovieItem movie;
MovieListItem(this.movie);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(width: 10, color: Color(0xffe2e2e2)))
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// 1
getMovieRankWidget(),
SizedBox(height: 12),
// 2. Details
getMovieContentWidget(),
SizedBox(height: 12),
// 3. Movie introduction
getMovieIntroduceWidget(),
SizedBox(height: 12,),),); }// Movie ranking
Widget getMovieRankWidget() {
return Container(
padding: EdgeInsets.fromLTRB(9.4.9.4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Color.fromARGB(255.238.205.144)
),
child: Text(
"No.${movie.rank}",
style: TextStyle(fontSize: 18, color: Color.fromARGB(255.131.95.36)))); }// Details
Widget getMovieContentWidget() {
return Container(
height: 150,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
getContentImage(),
getContentDesc(),
getDashLine(),
getContentWish()
],
),
);
}
Widget getContentImage() {
return ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(movie.imageURL)
);
}
Widget getContentDesc() {
return Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
getTitleWidget(),
SizedBox(height: 3,),
getRatingWidget(),
SizedBox(height: 3,),
getInfoWidget()
],
),
),
);
}
Widget getDashLine() {
return Container(
width: 1,
height: 100,
child: DashedLine(
axis: Axis.vertical,
dashedHeight: 6,
dashedWidth: . 5,
count: 12,),); } Widget getTitleWidget() {return Stack(
children: <Widget>[
Icon(Icons.play_circle_outline, color: Colors.redAccent,),
Text.rich(
TextSpan(
children: [
TextSpan(
text: "" + movie.title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold
)
),
TextSpan(
text: "(${movie.playDate})",
style: TextStyle(
fontSize: 18,
color: Colors.black54
),
)
]
),
maxLines: 2,)]); } Widget getRatingWidget() {return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
StarRating(rating: movie.rating, size: 18,),
SizedBox(width: 5),
Text("${movie.rating}")],); } Widget getInfoWidget() {// 1. Get the type string
final genres = movie.genres.join("");
final director = movie.director.name;
var castString = "";
for (final cast in movie.casts) {
castString += cast.name + "";
}
// 2. Create the Widget
return Text(
"$genres / $director / $castString",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16)); } Widget getContentWish() {return Container(
width: 60,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20,),
Image.asset("assets/images/home/wish.png", width: 30,),
SizedBox(height: 5,),
Text(
"Want to see",
style: TextStyle(fontSize: 16, color: Color.fromARGB(255.235.170.60() [() [() [() }// The name of the movie is
Widget getMovieIntroduceWidget() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Color(0xfff2f2f2),
borderRadius: BorderRadius.circular(5)
),
child: Text(movie.originalTitle, style: TextStyle(fontSize: 18, color: Colors.black54),), ); }}Copy the code
Note: All content will be published on our official website. Later, Flutter will also update other technical articles, including TypeScript, React, Node, Uniapp, MPvue, data structures and algorithms, etc. We will also update some of our own learning experiences