Full Flutter example

Keywords: Android JSON network SDK iOS

With this understanding and exposure to Flutter, you can learn how to develop a project using Flutter in its entirety.In fact, in Flutter, everything is a widget, and our interface is stacked with widgets.

A Flutter project involves the following points:

  • Project Code Layering
  • Theme Style
  • Plug-in unit
  • Route
  • Network Data Interaction
  • Interface Layout and Refresh

    1. Layering of project code

A formal project whose code must be hierarchical reflects the architectural capabilities of the initiator.

Main working lib directory and pubspec.yaml for Flutter project:

  • main.dart:Flutter's entry function
  • Load.dart: Startup page, average lifetime 3-5 seconds
  • app.dart: Project master file
  • conf: Configuration file current or some macro-defined data file directory
  • Model: Data model catalog
  • pages: each UI, the Widget file
  • service: network request directory
  • Style: Custom style file (color, font, etc.)
  • utils: Tools directory

The unreasonable design of code hierarchy directly affects the maintainability and stability of code.

2. Theme Style

Flutter defaults to blue and white themes, while other themes need to be configured.Depending on the project, configure a red-grey style for the current needs:

#main.dart
void main() => runApp(MaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Flutter actual combat',
  //Custom Theme
  theme: mDefaultTheme,

));

//Custom Theme
final ThemeData mDefaultTheme = ThemeData(
  primaryColor: Colors.redAccent,
);

Colors.redAccent is the system theme, defined in colors.dart:

static const MaterialAccentColor redAccent = MaterialAccentColor(
    _redAccentValue,
    <int, Color>{
      100: Color(0xFFFF8A80),
      200: Color(_redAccentValue),
      400: Color(0xFFFF1744),
      700: Color(0xFFD50000),
    },
  );
  static const int _redAccentValue = 0xFFFF5252;

Of course, you can also customize some styles or colors, in the project style color.dart:

//Product color
class ProductColors{
  static const Color bgColor = Color(0xFFFFFFFF);
  static const divideLineColor = Color.fromRGBO(245, 245, 245, 1.0);
  static const typeColor = Color.fromRGBO(182, 9, 9, 1.0);
  static const piontColor = Color.fromRGBO(132, 95, 63, 1.0);
}

3. Plug-ins

It is impossible for developers to make their own wheels for each function and choose the right one. For a project, you can get twice the result with half the effort.

3.1 Add third-party libraries

Open the pubspec.yaml file to add a tripartite library, which you can use in https://pub.dev/flutter Many open source packages were found on (FQ required)

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  http: ^0.12.0
  flutter_webview_plugin: ^0.3.0
  flutter_swiper: 1.1.4
  • http: Network Request Plugin
  • flutter_webview_plugin: Some static page loads, using WebView
  • flutter_swiper: Animation Relay Effect

3.2 Import

swiper plug-in

Click Packages get to get the package you just added.

This allows you to use the library.

4. Routing

Routing is mainly used for interface switching and jumping, which is divided into static routing and dynamic routing

  • Static routing: interface jumps without additional parameters
  • Dynamic routing: interface jumps can carry additional parameters

4.1 Routing Initialization

void main() => runApp(MaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Flutter actual combat',
  //Custom Theme
  theme: mDefaultTheme,

  //Add Route
  routes: <String,WidgetBuilder>{
    "app": (BuildContext context) => App(),
    "company_info":(BuildContext context) => WebviewScaffold(
      url: "https://www.baidu.com",
      appBar: AppBar(
        title: Text('Company Introduction'),
        leading: IconButton(
            icon: Icon(Icons.home),
            onPressed: (){
              //Route to Home Interface
              Navigator.of(context).pushReplacementNamed('app');
            },
        ),
      ),
    ),
  },
  //Specify Load Page
  home: LoadingPage(),

));

4.2 Static Routing

Navigator.of(context).pushReplacementNamed('company_info');

4.3 Dynamic Routing

Navigator.push(context,MaterialPageRoute(builder: (context) => AboutContactPage()));

perhaps

Navigator.push(context,MaterialPageRoute(builder: (context) => NewsDetailPage(item: item)),

Data Receive Processing:

class NewsDetailPage extends StatelessWidget{
  final NewsItemModal item;

  NewsDetailPage({Key key,@required this.item}) : super(key:key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(item.title),
      ),
      body:  Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(item.content),
      ),
    );
  }
}

V. Network Data Interaction

Network data interaction generally involves URL s, data models, data interaction modes (Get, Post), etc.

5.1 URL Definition

Define macro variables in configuration

class Config{
  static const String IP = '192.168.2.5';
  static const String PORT = '8080';
}

5.2 Data Model

//News List Item Data Conversion
class NewsItemModal{
  String author;//author
  String title;//Title
  String content;//content

  NewsItemModal({
    this.author,
    this.title,
    this.content,
  });

  factory NewsItemModal.fromJson(dynamic json){
    return NewsItemModal(
      author: json['author'],
      title: json['title'],
      content: json['content'],
    );
  }
}

//News List Data Conversion
class NewsListModal{

  List<NewsItemModal> data;
  NewsListModal(this.data);

  factory NewsListModal.fromJson(List json){
    return NewsListModal(
        json.map((i) => NewsItemModal.fromJson((i))).toList()
    );
  }
}

5.3 Data Interaction Mode

import 'package:http/http.dart' as http;
import 'dart:convert';
import '../conf/configure.dart';

//Get news data
getNewsResult() async {
  String url = 'http://' + Config.IP + ':' + Config.PORT + '/?action=getNews';

  var res = await http.get(url);
  String body = res.body;

  var json= jsonDecode(body);
  print(json);

  return json['items'] as List;
}

6. Interface Layout and Refresh

6.1 Startup Page Loading

An interface that lasts 3-5 seconds

class LoadingPage extends StatefulWidget{
  @override
  _LoadingState createState() => _LoadingState();
}

class _LoadingState extends State<LoadingPage>{

  @override
  void initState(){
    super.initState();

    //Pause on load page for 3 seconds
    Future.delayed(Duration(seconds: 3),(){
      print('Flutter Enterprise Station Startup...');
      Navigator.of(context).pushReplacementNamed("app");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Center(
        child: Stack(
          children: <Widget>[
            //Load Page Background Map
            Image.asset(
              'assets/images/loading.jpeg'
            ),

            Center(
              child: Text(
                'Flutter',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 36.0,
                  decoration: TextDecoration.none
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

6.2 Relay Pictures

Roadcasting pictures are widely used, such as advertising.

In the Resource Configuration Picture, add a picture

 # To add assets to your application, add an assets section, like this:
  assets:
  - assets/images/loading.jpeg
  - assets/images/company.jpg

  #Roadcast Pictures
  - assets/images/banners/1.jpeg
  - assets/images/banners/2.jpeg
  - assets/images/banners/3.jpeg
  - assets/images/banners/4.jpeg

Using the Swiper plug-in

import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart';

class BannerWidget extends StatelessWidget{

  //Picture Path
  List<String> banners = <String>[
    'assets/images/banners/1.jpeg',
    'assets/images/banners/2.jpeg',
    'assets/images/banners/3.jpeg',
    'assets/images/banners/4.jpeg',
  ];

  @override
  Widget build(BuildContext context) {

    //Calculate proportionate width to height
    double width = MediaQuery.of(context).size.width;
    double height = width * 540.0 / 1080.0;
    return Container(
      width: width,
      height: height,
      //Roadcasting Component
      child: Swiper(
        itemBuilder: (BuildContext context, index){
          return Container(
            //Left and right margins
            margin: EdgeInsets.only(left: 5, right: 5),
            child: Image.asset(
              banners[index],
              width: width,
              height: height,
              fit: BoxFit.cover,
            ),
          );
        },
        //Number of Rolls
        itemCount: banners.length,
        //direction
        scrollDirection: Axis.horizontal,
        //Whether to Play Automatically
        autoplay: true,
      ),
    );
  }
}

6.3 Main interface (with navigation bar)

import 'package:flutter/material.dart';
import 'pages/about_us_page.dart';
import 'pages/home_page.dart';
import 'pages/news_page.dart';
import 'pages/product_page.dart';

class App extends StatefulWidget {
  @override
  AppState createState() => AppState();
}

class AppState extends State<App> {
  //Currently Selected Page Index
  var _currentIndex = 0;

  HomePage homePage;
  ProductPage productPage;
  NewsPage newsPage;
  AboutUsPage aboutUsPage;

  //Return different pages based on the current index
  currentPage(){
    switch(_currentIndex){
      case 0:
        if(homePage == null){
          homePage = HomePage();
        }
        return homePage;
      case 1:
        if(productPage == null){
          productPage = ProductPage();
        }
        return productPage;

      case 2:
        if(newsPage == null){
          newsPage = NewsPage();
        }
        return newsPage;
      case 3:
        if(aboutUsPage == null){
          aboutUsPage = AboutUsPage();
        }
        return aboutUsPage;

    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Enterprise Station Actual Warfare'),
        leading: Icon(Icons.home),
        actions: <Widget>[
          //Right margin
          Padding(
            padding: EdgeInsets.only(right: 20.0),
            child: GestureDetector(
              onTap: () {},
              child: Icon(
                Icons.search,
              ),
            ),
          ),
        ],
      ),

      body: currentPage(),

      //Bottom navigation bar
      bottomNavigationBar: BottomNavigationBar(
          //Set the color of the selected item by fixedColor
          type: BottomNavigationBarType.fixed,
          currentIndex: _currentIndex,
          onTap: ((index) {
            setState(() {
              _currentIndex = index;
            });
          }),
          //Bottom navigation bar
          items: [
            BottomNavigationBarItem(
              title: Text(
                'home page',
              ),
              icon: Icon(Icons.home),
            ),
            BottomNavigationBarItem(
              title: Text(
                'product',
              ),
              icon: Icon(Icons.apps),
            ),
            BottomNavigationBarItem(
              title: Text(
                'Journalism',
              ),
              icon: Icon(Icons.fiber_new),
            ),
            BottomNavigationBarItem(
              title: Text(
                'About us',
              ),
              icon: Icon(Icons.insert_comment),
            ),
          ]),
    );
  }
}

6.4 Application of ListView

import 'package:flutter/material.dart';
import '../model/news.dart';
import '../services/news.dart';
import 'news_detail_page.dart';

//News Page
class NewsPage extends StatefulWidget {
  @override
  NewsPageState createState() => NewsPageState();
}

class NewsPageState extends State<NewsPage> {
  NewsListModal listData = NewsListModal([]);

  //Get News List Data
  void getNewsList() async {
    var data = await getNewsResult();
    NewsListModal list = NewsListModal.fromJson(data);

    setState(() {
      listData.data.addAll(list.data);
    });
  }

  @override
  void initState() {
    getNewsList();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //List with Separator
      body: ListView.separated(
        //Arrangement Direction Vertical and Horizontal
        scrollDirection: Axis.vertical,
        //Separator builder
        separatorBuilder: (BuildContext contex, int index) => Divider(
              height: 1.0,
              color: Colors.grey,
            ),
        itemCount: listData.data.length,
        //List Item Builder
        itemBuilder: (BuildContext contex, int index) {

          //News List Item Data
          NewsItemModal item = listData.data[index];

          return ListTile(
            title: Text(item.title),
            subtitle: Text(item.content),
            leading: Icon(Icons.fiber_new),
            trailing: Icon(Icons.arrow_forward),
            contentPadding: EdgeInsets.all(10.0),
            enabled: true,
            //Jump to the news details page
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => NewsDetailPage(item: item)),
              );
            },
          );
        },
      ),
    );
  }
}

6.5 Text Box Operation

Contains text box configuration and data manipulation

import 'package:flutter/material.dart';
import '../services/contact.dart';

class AboutContactPage extends StatefulWidget{
  @override
  AboutContactPageState createState() => AboutContactPageState();
}

class AboutContactPageState extends State<AboutContactPage>{

  //Text Editing Controller
  TextEditingController controller = TextEditingController();

  //Submit data
  void commit(){
    if(controller.text.length == 0){
      showDialog(context: context,builder: (context) => AlertDialog(title: Text('Please enter content'),),);
    } else{
      var info = contactCompany(controller.text);
      print(info);
    }
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Leave a message for me'),
      ),
      body: Container(
        color: Colors.white,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Image.asset(
              'assets/images/company.jpg',
              fit: BoxFit.cover,
            ),
            SizedBox(
              height: 40.0,
            ),
            SizedBox(
              width: 380.0,
              child: TextField(
                controller: controller,
                decoration: InputDecoration(
                  hintText: 'Please leave a message',
                  labelText: 'Please leave a message',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.person),
                ),
              ),
            ),
            SizedBox(
              height: 40.0,
            ),
            SizedBox(
              width: 220.0,
              height: 48.0,
              child: RaisedButton(
                child: Text('Leave us a message',style: TextStyle(fontSize: 16.0),),
                color: Theme.of(context).primaryColor,//Colors.redAccent,
                colorBrightness: Brightness.dark,
                textColor: Colors.white,
                padding: EdgeInsets.only(
                  left: 20.0,
                  right: 20.0,
                  top: 5.0,
                  bottom: 5.0,
                ),
                shape: RoundedRectangleBorder(
                  side: BorderSide(
                    width: 1.0,
                    color: Colors.white,
                    style: BorderStyle.solid,
                  ),
                  borderRadius: BorderRadius.only(
                    topRight: Radius.circular(4.0),
                    topLeft: Radius.circular(4.0),
                    bottomLeft: Radius.circular(4.0),
                    bottomRight: Radius.circular(4.0),
                  ),
                ),
                onPressed: (){
                  commit();
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

7. Points of Attention

  • =>is an abbreviation of one-line function in Dart
  • StatelessWidget represents a component with only one state, corresponding to StatefulWidget (indicating that there may be multiple states).
  • Widget components are built to describe their internal structure.Here, build means that the system components used to build MyApp are MaterialApp.
  • Home tag value: Scaffold is a component provided in Material library where we can set the navigation bar, title, and body properties that contain the home screen widget tree.You can see here that AppBar and a Text are added to the page.
  • Center is a component that can center subcomponents

Posted by tomdumont on Sat, 14 Sep 2019 09:17:00 -0700