[Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть IV)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
03-Июн-2021 14:33

Всем добрый денек! Надеюсь после первых трех статей, эта вам покажется не менее полезной.Сегодня я постараюсь простым языком объяснить MVC паттерн.И конечно же покажу все на практике!Поехали!Наш план
  • Часть 1 - введение в разработку, первое приложение, понятие состояния;
  • Часть 2 - файл pubspec.yaml и использование flutter в командной строке;
  • Часть 3 - BottomNavigationBar и Navigator;
  • Часть 4 (текущая статья) - MVC. Мы будем использовать именно этот паттерн, как один из самых простых;
  • Часть 5 - http пакет. Создание Repository класса, первые запросы, вывод списка постов;
  • Часть 6 - Работа с картинками, вывод картинок в виде сетки, получение картинок из сети, добавление своих в приложение;
  • Часть 7 - Создание своей темы, добавление кастомных шрифтов и анимации;
  • Часть 8 - Немного о тестировании;
Зачем MVC и прочие архитектурные принципы?Возможно новичкам сначала совсем непонятно, для какой цели использовать архитектурные принципы, ведь без них хорошо.Зачем все усложнять?Наиболее веские причины:
  • Сложность кода - когда у вас небольшое приложение с одним или двумя экранами, будь это Flutter или нативное Android / iOS приложение, вы возможно спокойно обойдетесь без понимания принципов архитектуры. Другое дело, когда у проект приличных размеров, вы не сможете обойтесь без единых правил и принципов.
  • Сложность задачи - например: вам необходимо реализовать переключение между 3-мя, 5-ю или даже 10-ю темами (возможно задача не является распространенной). Без четкого понимания архитектуры это так не так просто сделать.
  • Сложность поддержки - если вы разрабатываете огромный коммерческий проект, скажем: Портал какого-либо города, объединенный с различными сервисами (карта, гостиницы и т.д.) вы по крайнее мере должны иметь команду. Каждый член команды должен действовать слаженно. А чтобы действовать слаженно нужно понимать чужой код. Без какого-либо единого подхода в вашей команде возникнет хаос и система потерпит крах.
Это наиболее распространенные причины по моему мнению Также хорошая архитектура приложения наводит порядок в голове программиста :)В чем суть MVC?MVC (Model - View - Controller) является довольно старым изобретением и содержит три основных компонента:
  • Модель (Model) представляет собой данные, что и является сутью любого приложения. Само по себе приложение невозможно без данных. Вернемся к примеру из предыдущей главы: список поняшек. В том случае данными являлись пони, которые мы отображали в виде списка. Модель должна обратывать все, что с ней связано (сохранение и манипулирование данными). Ещё модель может иметь отношения (один к одному, один ко многих, многие ко многим). Практически, модель - это класс Dart, например: Pony
  • Представление (View), в нашем случае это Flutter виджеты (кнопки, текст, списки), которые будут отображать нашу модель. View должно знать о модели и о её свойствах. Пользователь взаимодействует только с представлением и инициирует различные события (нажатие кнопки, свайп пальцем и т.д.). События могут оказывать влияние на модель, это происходит не напрямую, а через контроллер. Практически, представление - это виджеты: Text, Scaffold, AppBar, ListView и другие.
  • Контроллер (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 не исчерпываются.К тому же мы ещё не раз будет создавать новые контроллеры и модели. Так что все впереди! До скорой встречи.Полезные ссылки:
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_dart, #_flutter, #_dart, #_android, #_mobile_development, #_flutter, #_mvc, #_patterns, #_razrabotka_pod_android (
Разработка под Android
)
, #_dart, #_flutter
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 12:16
Часовой пояс: UTC + 5