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