In my opinion, learning a new language (fast and efficient learning) must be through practice, and the best way is to do projects. I will simply write a jingdong Demo here.

Scalfold Widget is used to describe the main structure of a page. A MaterialApp consists of multiple Scalfold pages, and the general results of each Scalfold are as follows:

  • AppBar: Top navigation bar
  • Body: Intermediate content body
  • BottomNavigationBar: BottomNavigationBar

On the first day, I set up the project framework and realized the functions of the home page.

Knowledge points used

  1. BottomNavigationBarBottom navigation bar basic properties

  1. Named Routes: For more information see the Detailed description of the Flutter navigation and Routing stack

  2. Screen adaptation: The flutter_screenUtil plugin is used, which has the following properties

Pass in the size of the design, px, px, px! // ScreenUtil().setwidth (540) // ScreenUtil().setheight (200) // ScreenUtil().setsp (24) // ScreenUtil().setwidth (540) // ScreenUtil().setheight (200) // ScreenUtil().setsp (24 ScreenUtil().setSp(24, allowFontScalingSelf: ScreenUtil().setsp (24, allowFontScalingSelf: ScreenUtil().setsp (24, allowFontScalingSelf: ScreenUtil().pixelRatio // Pixel density of the device ScreenUtil().screenWidth // Device width ScreenUtil().screenheight // device height ScreenUtil(). StatusBarHeight // statusBarHeight bangs are higher unit dp ScreenUtil(). TextScaleFactor ScreenUtil().scaleWidth // ScreenUtil().scaleheight // ScreenUtil().scaleHeight // ScreenUtil()Copy the code
  1. Network request usagedioPlug-in implementation, detailed explanation can see the official website:Github.com/flutterchin…
import 'package:dio/dio.dart';

void main() async {
  var dio = Dio();
  final response = await dio.get('https://google.com');
  print(response.data);
}
Copy the code
  1. Use of the rotation chartswiperA plugin

SwiperPagination

BottomCenter The distance between the page indicator and the container border margin EdgeInsets. All (10.0) The style of the page indicator Fraction Custom style Builder swiperpagination.dotsCopy the code
  1. Page frame usageListViewImplement the list

  1. The list of goods is usedWrap, streaming layout, automatic wrapping
Direction: the direction of the mainAxis. The default is horizontal. Alignment: Alignment in the main axis direction. The default value is Start. Spacing: The spacing along the main axis. RunAlignment: Alignment of the run. Run can be interpreted as a new row or column, or as a new row if the layout is horizontal. RunSpacing: The spacing between runs. CrossAxisAlignment: Alignment in the direction of a crossAxis. TextDirection: indicates the textDirection. VerticalDirection: defines the order in which children are placed. The default value is down.Copy the code

Project construction

Dart and four bottom tabs (home.dart, category.dart, cart.dart, user.dart).

Just post the main code here:

bottomNavigationBar: BottomNavigationBar( currentIndex:_currentIndex , onTap: (index){ setState(() { _currentIndex=index; }); }, type:BottomNavigationBarType.fixed , fixedColor:Colors.red, items: [ BottomNavigationBarItem( icon: Icon(Icons. Home), label: "home"), BottomNavigationBarItem(Icon: Icon(Icons. Category), label: BottomNavigationBarItem(icon: icon (Icons. Shopping_cart), label: "cart"), BottomNavigationBarItem(icon: Icon(Icons. People), label: "my")],),Copy the code

Configuring named Routes

To facilitate unified management, create a Router folder and create a router.dart class in the folder to manage routes

Final Map<String,Function> routes = {'/': (context) => Tabs(),arguments,),}; Var onGenerateRoute = (RouteSettings Settings) {final String? name = settings.name; final Function? pageContentBuilder = routes[name]; if (pageContentBuilder ! = null) { if (settings.arguments ! = null) { final Route route = MaterialPageRoute( builder: (context) => pageContentBuilder(context, arguments: settings.arguments)); return route; } else { final Route route = MaterialPageRoute(builder: (context) => pageContentBuilder(context)); return route; }}};Copy the code

Screen adaptation

Here I choose Flutter_screenUtil for screen adaptation. Flutter_screenutil is added in Pubspec.yaml by default using 750*1334 designs as the standard

Flutter_screenutil: ^ 5.0.0 + 2Copy the code

Then click Pub get to pull. Create a Services folder and create the Screen_Adapter.dart class to implement common functions

import 'package:flutter_screenutil/flutter_screenutil.dart'; Static height(num value) {return ScreenUtil().setheight (value); } static width(num value) { return ScreenUtil().setWidth(value); } static size(num value) { return ScreenUtil().setSp(value); } static getScreenWidth() {return ScreenUtil().screenWidth; } static getScreenHeight() {return ScreenUtil().screenheight; } static double statusBarHeight = ScreenUtil().statusbarheight; Static double bottomBarHeight = ScreenUtil().bottombarheight; }Copy the code

The specific implementation

The overall framework of the page is realized using ListView, and the content is divided into the following three blocks:

  • The Swiper plugin is used to display the banner area
  • Guess your favorite horizontal scrolling list via ListView
  • Vertical scrolling list of top recommendations, via Wrap

Implement the banner area of the broadcast map

Firstly, flutter_swiper_NULl_safety: ^1.0.2 was introduced. The rotation chart was the data obtained from the network. Dio: ^4.0.0 was also introduced for network request, and then the pub GET pull was performed.

Dart creates the focus_model.dart model for the cast map, and the code inside is implemented as

class FocusModel { List<FocusItemModel> result=[]; FocusModel({required this.result}); FocusModel.fromJson(Map<String, dynamic> json) { if (json['result'] ! = null) { json['result'].forEach((v) { result.add(new FocusItemModel.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['result'] = this.result.map((v) => v.toJson()).toList(); return data; } } class FocusItemModel { String? sId; // Nullable type String? title; String? status; String? pic; String? url; FocusItemModel({this.sId, this.title, this.status, this.pic, this.url}); FocusItemModel.fromJson(Map<String, dynamic> json) { sId = json['_id']; title = json['title']; status = json['status']; pic = json['pic']; url = json['url']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['_id'] = this.sId; data['title'] = this.title; data['status'] = this.status; data['pic'] = this.pic; data['url'] = this.url; return data; }}Copy the code

Get banner data

/ / get hot recommended data _getBestProductData () async {var API = 'https://jdmall.itying.com/api/plist?is_best=1'; var result = await Dio().get(api); var bestProductList = ProductModel.fromJson(result.data); setState(() { this._bestProductList = bestProductList.result; }); }Copy the code

Create a caroute diagram

Widget _swiperWidget() { if (this._focusData.length > 0) { return Container( child: AspectRatio( aspectRatio: 2 / 1, child: Swiper( itemBuilder: (BuildContext context, int index) { String pic = this._focusData[index].pic; pic = Config.domain + pic.replaceAll('\', '/'); return new Image.network( "${pic}", fit: BoxFit.fill, ); }, itemCount: this._focusData.length, pagination: new SwiperPagination(), autoplay: true), ), ); } else {return Text(' Loading... '); }}Copy the code

The specific code is as follows:

List _focusData = [];
@override
void initState() {
  super.initState();
  _getFocusData();
}

@override
Widget build(BuildContext context) {
  return ListView(
    children: <Widget>[
      _swiperWidget(),
    ],
  );
}
Copy the code

Then run the project to achieve this effect, the rotation map function is ready

Achieve the effect of guessing you like

Encapsulate a method and return a Widget

Widget _titleWidget(value) {
  return Container(
    height: ScreenAdapter.height(32),
    margin: EdgeInsets.only(left: ScreenAdapter.width(20)),
    padding: EdgeInsets.only(left: ScreenAdapter.width(20)),
    decoration: BoxDecoration(
        border: Border(
            left: BorderSide(
      color: Colors.red,
      width: ScreenAdapter.width(10),
    ))),
    child: Text(
      value,
      style: TextStyle(color: Colors.black54),
    ),
  );
}
Copy the code

Get guess what you like about web data

_getHotProductData() async {var API = '${config.domain} API /plist? is_hot=1'; var result = await Dio().get(api); var hotProductList = ProductModel.fromJson(result.data); setState(() { this._hotProductList = hotProductList.result; }); }Copy the code

Create a horizontal list of guesses you like

// If (_hotproductList.length > 0) {return Container(height: ScreenAdapter.height(234), padding: EdgeInsets.all(ScreenAdapter.width(20)), child: Listview. builder(// Set scrollDirection: Axis. Horizontal, itemBuilder: SPic = _hotProductList[index].spic; contxt = _hotProductList[index].spic; SPic = config. domain + spic. replaceAll('\', '/'); return Column( children: <Widget>[ Container( height: ScreenAdapter.height(140), width: ScreenAdapter.width(140), margin: EdgeInsets.only(right: ScreenAdapter.width(21)), child: Image.network(sPic, fit: BoxFit.cover), ), Container( padding: EdgeInsets.only(top: ScreenAdapter.height(10)), height: Screenadapter.height (44), child: Text("¥${_hotProductList[index]. Price}", style: TextStyle(color: red) Colors.red), ), ) ], ); }, itemCount: _hotProductList.length, ), ); } else { return Text(""); }}Copy the code

Implementation effect

Implement popular recommendation features

Get data on popular recommendations

_getBestProductData() async { var api = '${Config.domain}api/plist? is_best=1'; var result = await Dio().get(api); var bestProductList = ProductModel.fromJson(result.data); setState(() { this._bestProductList = bestProductList.result; }); }Copy the code

Creating an item list

Widget _recProductListWidget() { var itemWidth = (ScreenAdapter.getScreenWidth() - 30) / 2; return Container( padding: EdgeInsets.all(10), child: Wrap( runSpacing: 10, spacing: 10, children: This._bestproductlist.map ((value) {String sPic = value.spic == null? '' : value.sPic; sPic = Config.domain+sPic.replaceAll('\', '/'); return Container( padding: EdgeInsets.all(10), width: itemWidth, decoration: BoxDecoration( border: Border.all( color: Color.fromrgbo (233, 233, 233, 0.9), width: 1)), child: Column(children: <Widget>[Container(width: Double. Infinity, child: AspectRatio(AspectRatio: 1/1) Image.network( "${sPic}", fit: BoxFit.cover, ), ), ), Padding( padding: EdgeInsets.only(top: ScreenAdapter.height(20)), child: Text( "${value.title}", maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black54), ), ), Padding( padding: EdgeInsets.only(top: ScreenAdapter.height(20)), child: Stack(children: <Widget>[Align: Align. CenterLeft, child: Text("¥${value.price}", style: TextStyle(color: Colors.red, fontSize: 16), ), ), Align( alignment: Alignment.centerRight, child: Text("¥${value.oldprice}", style: TextStyle(color: color.black54, fontSize: 14, decoration: color: color. TextDecoration.lineThrough)), ) ], ), ) ], ), ); }).toList(), ), ); }Copy the code

Implementation effect