[Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть IV)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Всем добрый денек! Надеюсь после первых трех статей, эта вам покажется не менее полезной.Сегодня я постараюсь простым языком объяснить 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
===========
Похожие новости:
- [Разработка под Android] Всё о PendingIntents (перевод)
- [Разработка под Android, Kotlin] Proto DataStore + AndroidX Preferences на Kotlin
- [Разработка под Android] Все новинки Android 12. Обзор для разработчиков
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть II)
- [Java, Разработка под Android] Инициализация Rx цепочки
- [Информационная безопасность, Разработка под Android, Геоинформационные сервисы, Смартфоны] Google собирает данные геолокации со смартфонов, даже если запретить отслеживание
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть I)
- [Flutter] Dart: Быстрые неизменяемые коллекции (перевод)
- [Информационная безопасность, Разработка мобильных приложений, Разработка под Android, Google API] Обновляемся на новую версию API Android по наставлению Google
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android, Дизайн мобильных приложений] За что банит Apple(и Google)
Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_dart, #_flutter, #_dart, #_android, #_mobile_development, #_flutter, #_mvc, #_patterns, #_razrabotka_pod_android (
Разработка под Android
), #_dart, #_flutter
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:49
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Всем добрый денек! Надеюсь после первых трех статей, эта вам покажется не менее полезной.Сегодня я постараюсь простым языком объяснить MVC паттерн.И конечно же покажу все на практике!Поехали!Наш план
# блок зависимостей
dependencies: flutter: sdk: flutter # подключение необходимых pub-пакетов # используется для произвольного размещения # компонентов в виде сетки flutter_staggered_grid_view: ^0.4.0 # этот пакет содержит вспомогательные # элементы для реализации MVC паттерна # в Flutter приложении mvc_pattern: ^7.0.0 # большая часть данных будет браться из сети, # поэтому мы будем использовать http для # осуществления наших запросов http: ^0.13.3 flutter pub get
Воспользуемся готовым кодом из прошлых частей и сделаем нашу домашнюю страницу в соотвествии с паттерном 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); } } 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, ), ); } } Вуаля! Все работает как прежде. Немного слов об архитектуре Flutter приложенийFlutter является декларативным фреймворком и поэтому архитектура Flutter приложения всегда сводится к управлению состоянием StatefulWidget'ов.Существует множество подходов по управлению состоянием.Более подробно об этом написано в самой документации по FlutterЗаключениеПоздравляю вас.Хотелось бы отметить, что на этом знания об MVC не исчерпываются.К тому же мы ещё не раз будет создавать новые контроллеры и модели. Так что все впереди! До скорой встречи.Полезные ссылки: =========== Источник: habr.com =========== Похожие новости:
Разработка под Android ), #_dart, #_flutter |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:49
Часовой пояс: UTC + 5