Flutter Basics for Beginners (Part IV)

Good day everyone! After the first three articles, I hope you find this one just as useful.





Today I will try to explain the MVC pattern in simple language.





And of course I will show everything in practice!





Go!





Our plan
  • Part 1  - introduction to development, first appendix, concept of state;





  • Part 2  - pubspec.yaml file and using flutter on the command line;





  • Part 3 - BottomNavigationBar and Navigator;





  • Part 4 (current article) - MVC. We will use this particular pattern as one of the simplest;





  • Part 5 - http package. Creation of the Repository class, first requests, listing of posts;





  • Part 6 - Working with pictures, displaying pictures in the form of a grid, receiving pictures from the network, adding your own to the application;





  • Part 7 - Creating your own theme, adding custom fonts and animations;





  • Part 8 - A little about testing;





Why MVC and other architectural principles?

Perhaps at first it is completely incomprehensible to beginners for what purpose to use architectural principles, because without them it is good.





Why complicate things?





The most compelling reasons:





  • Complexity of the code - when you have a small application with one or two screens, be it Flutter or a native Android / iOS application, you can probably do without understanding the principles of architecture. Another thing is when the project has a decent size, you cannot do without uniform rules and principles.





  • The complexity of the task - for example: you need to implement switching between 3, 5 or even 10 topics (perhaps the task is not common). Without a clear understanding of the architecture, this is not so easy to do.





  • Complexity of support - if you are developing a huge commercial project, say: A portal of a city, combined with various services (map, hotels, etc.), you should at least have a team. Each team member must act in a coordinated manner. And in order to act harmoniously, you need to understand someone else's code. Without some kind of unified approach, your team will be chaos and the system will collapse.





These are the most common reasons in my opinion.





Also, a good application architecture puts things in order in the programmer's head :)





What is the essence of MVC?

MVC (Model - View - Controller) :





  1. (Model) , . . : . , . , ( ). ( , , ). , - Dart, : Pony





  2. (View), Flutter (, , ), . View . ( , ..). , , . , - : Text, Scaffold, AppBar, ListView .





  3. (Controller) ( ) . - . . , , , : HomeController





.





MVC

.





Flutter pub-, II pubspec.yaml



:





#  
dependencies:
  flutter:
    sdk: flutter

  #   pub-

  #    
  #    
  flutter_staggered_grid_view: ^0.4.0

  #    
	#    MVC 
	#  Flutter 
  mvc_pattern: ^7.0.0

  #       ,
  #     http 
  #   
  http: ^0.13.3


      
      



pub get



:





flutter pub get
      
      



Android Studio ( Flutter commands):





MVC.





:





:





, (View) , .





)





controllers



home_controller.dart



:





import 'package:flutter/material.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
import '../models/tab.dart';

//  mvc_pattern 
//    ControllerMVC,
//    setState 
class HomeController extends ControllerMVC {

  //     
  static HomeController _this;
  static HomeController get controller => _this;

  //    factory   
  //   HomeController
  //      
  //       Singleton
  //      
  //  HomeController
  factory HomeController() {
    if (_this == null) _this = HomeController._();
    return _this;
  }

  HomeController._();

  // GlobalKey    ,
  //      
  //  ,     
  // NavigatorState -  Navigator 
  //  _       ,
  //   private ,  
  //       _navigatorKeys
  final _navigatorKeys = {
    TabItem.POSTS: GlobalKey<NavigatorState>(),
    TabItem.ALBUMS: GlobalKey<NavigatorState>(),
    TabItem.TODOS: GlobalKey<NavigatorState>(),
  };

  //   get   getter
  //       _navigatorKeys,
  //     
  //     (   )
  Map<TabItem, GlobalKey> get navigatorKeys => _navigatorKeys;

  //   
  var _currentTab = TabItem.POSTS;

  //         
  TabItem get currentTab => _currentTab;

  //   
  //     selectTab 
  //       HomePage
  //  ,   mvc_pattern
  //     setState 
  //  ,   
  void selectTab(TabItem tabItem) {
    setState(() => _currentTab = tabItem);
  }


}
      
      



HomePage.dart







:





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

import '../../models/tab.dart';

import '../../controllers/home_controller.dart';

import 'bottom_navigation.dart';
import 'tab_navigator.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

//      
// StateMVC   mvc_pattern
class _HomePageState extends StateMVC {

  //    
  HomeController _con;

  // super   StateMVC  
  //    
  _HomePageState() : super(HomeController()) {
    //     
    _con = HomeController.controller;
  }


  //     
  //  currentTab  selectTab 
  //    
  @override
  Widget build(BuildContext context) {
    // WillPopScope  
    //   Back
    return WillPopScope(
      //    back   
      //    :
      //        ()
      //    Back,     
      //       
      //  : c   ,    ,
      //       
      onWillPop: () async {
          if (_con.currentTab != TabItem.POSTS) {
            if (_con.currentTab == TabItem.TODOS) {
              _con.selectTab(TabItem.ALBUMS);
            } else {
              _con.selectTab(TabItem.POSTS);
            }
            return false;
          } else {
            return true;
          }

      },
      child: Scaffold(
        // Stack     
        //  ,    
        //  ,      
        body: Stack(children: <Widget>[
          _buildOffstageNavigator(TabItem.POSTS),
          _buildOffstageNavigator(TabItem.ALBUMS),
          _buildOffstageNavigator(TabItem.TODOS),
        ]),
        // MyBottomNavigation   
        bottomNavigationBar: MyBottomNavigation(
          currentTab: _con.currentTab,
          onSelectTab: _con.selectTab,
        ),
      ),);
  }

  //     - ,   
  Widget _buildOffstageNavigator(TabItem tabItem) {
    return Offstage(
      // Offstage   :
      //      
      //   ,    
      offstage: _con.currentTab != tabItem,
      // TabNavigator   
      child: TabNavigator(
        navigatorKey: _con.navigatorKeys[tabItem],
        tabItem: tabItem,
      ),
    );
  }

}
      
      



, HomePage HomeController



.





! .





Flutter

Flutter Flutter StatefulWidget



'.





.





Flutter





.





, MVC .





.





! .





:





  • mvc_pattern





  • MVC Overview









  • Github








All Articles