В процессе разработки приложений Flutter важную роль в структуре приложения играют управление состоянием и управление маршрутизацией. Текущие основные решения включают официальный провайдер Google, сторонние GetX, Bloc, fish-redux и т. д. После многочисленных практических сравнений GetX выделяется.
GETX - это легкое и мощное решение с высокой производительностью государственного управления, интеллектуальным впрыском зависимости маршрутизации и удобным управлением.
В этой статье вы узнаете, как интегрировать GetX для создания собственной среды приложений Flutter с нуля.
0. Интеграция с GetX
добавить зависимости
существуетpubspec.yaml
Добавьте зависимости GetX в файл следующим образом:
dependencies:
flutter:
sdk: flutter
get: ^4.5.1
Инициализировать GetX
Чтобы использовать GETX, вам нужно инициализировать GETX, установить по умолчаниюMaterialApp
заменитьGetMaterialApp
Вы можете следующим образом:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
1. Управление статусом
GetX предоставляет два метода управления реактивным состоянием:адаптивная переменнаяпуть игосударственный менеджерСпособ.
адаптивная переменная
определение
Чтобы определить реактивную переменную, просто добавьте.obs
Затем переменная может быть определена как реактивная переменная:
var count = 0.obs;
Реактивные переменные могут использоваться для любого типа:
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// 自定义类 - 可以是任何类
final user = User().obs;
Получить значение реактивной переменной
звонить при использованииvalue
чтобы получить значение переменной. дляList
,Map
нет необходимости добавлять.value
.
String nameValue = name.value
bool isLoggedValue = isLogged.value
int countValue = count.value
double numberValue = number.value
String item = items[0] //不需要.value
int value = myMap['key'] //不需要.value
String name = user.value.name
обновить данные:
Для базовых типов данных просто переназначьте значение, чтобы обновить данные и обновить интерфейс через Obx:
name.value = "123"
isLogged.value = true
count.value = 1
number.value = 12.0
Для других типов данных необходимо вызватьupdate
Или обновление метода переменной, как показано ниже:
user.update((value) {
value?.name = "123";
});
Или используйте метод имени переменной, чтобы переназначить объект, например имя переменной.user
тогда вы можете использоватьuser()
метод обновления:
user(User(name: "abcd", age: 25));
обновить интерфейс
Использование реактивных переменных в интерфейсе просто оборачивает элемент управления, использующий переменную.Obx
То есть обновление ответов может быть реализовано, то есть значение переменной изменения автоматически освежает интерфейс:
Obx(() => Text("${count.value}"))
мониторинг изменения данных
Помимо использованияObx
В дополнение к автоматическому обновлению данных интерфейса GetX предоставляет множество ручных методов для отслеживания изменений данных в адаптивных переменных и выполнения пользовательской логики при изменении данных, например повторного запроса интерфейса после изменения данных.
-
ever
Срабатывает при изменении данных -
everAll
Аналогичен "ever", за исключением того, что он прослушивает изменения в нескольких реактивных переменных, и когда одна из них изменяется, запускается обратный вызов. -
once
Вызывается только при первом изменении переменной -
debounce
Антишейк, то есть вызов задерживается на определенное время, и только последнее изменение в течение указанного времени вызовет обратный вызов. Если задано время 1 секунда и есть 3 изменения данных, каждое с интервалом 500 миллисекунд, только последнее изменение вызовет обратный вызов. -
interval
Только последнее изменение в интервале вызовет обратный вызов. Если временной интервал установлен на 1 секунду, независимо от того, сколько раз вы нажмете в течение 1 секунды, только последний раз вызовет обратный вызов, а затем введите следующий временной интервал.
Как использовать:
///每次`count`变化时调用。
ever(count, (newValue) => print("$newValue has been changed"));
///只有在变量count在第一次被改变时才会被调用。
once(count, (newValue) => print("$newValue was changed once"));
///防DDos - 每当用户停止输入1秒时调用,例如。
debounce(count, (newValue) => print("debouce$newValue"), time: Duration(seconds: 1));
///忽略1秒内的所有变化,只有最后一次会触发回调。
interval(count, (newValue) => print("interval $newValue"), time: Duration(seconds: 1));
Пример
Реализуйте функциональность счетчика, используя реактивные переменные:
class CounterPage extends StatelessWidget {
var count = 0.obs;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Counter"),
),
body: Center(
child: Obx(() => Text("${count.value}", style: const TextStyle(fontSize: 50))),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => count ++,
),
);
}
}
Приведенный выше код реализует простую функцию счетчика, после тщательной проверки выясняется, что он не используется.StatefulWidget
Также может быть достигнуто автоматическое обновление счетчиков. В этом сила реактивных переменных.
государственный менеджер
GetX также предоставляет возможность использованияController
Для управления состоянием реализуйте собственный класс Controller, который наследуется отGetxController
, бизнес-логика обрабатывается в Контроллере и вызывается, когда нужно изменить данные состоянияupdate()
для уведомления об изменении данных.
Метод реализации:
class CounterController extends GetxController{
int count = 0;
void increment(){
count ++ ;
update();
}
}
Необходимо использовать при использовании в интерфейсеGetBuilder
Оберните его так, чтобы при изменении данных в контроллере вызывалсяupdate()
Элементы управления интерфейсом будут обновлены.
GetBuilder<CounterController>(
init: CounterController(), //Controller 首次初始化
builder: (controller) {
return Text("${controller.count}", style: const TextStyle(fontSize: 50));
})
Инициализация требуется при первом использовании Controller, а последующее использование того же Controller не требует инициализации, то есть init не нужно настраивать.
После инициализации вы можете использоватьGet.find()
Найдите соответствующий контроллер:
Пример
Реализуйте счетчик с помощью контроллера:
class CounterController extends GetxController{
int count = 0;
void increment(){
count ++ ;
update();
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Counter"),
),
body: Center(
child: Column(
mainAxisSize:MainAxisSize.min,
children: [
GetBuilder<CounterController>(
init: CounterController(), /// 初始化 Controller
builder: (controller) {
return Text("${controller.count}", style: const TextStyle(fontSize: 50));
}),
GetBuilder<CounterController>( ///没有进行初始化
builder: (controller) {
return Text("${controller.count}", style: const TextStyle(fontSize: 50));
}),
],
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
///使用 find 找到 Controller
CounterController controller = Get.find();
///调用 Controller 方法
controller.increment();
},
),
);
}
}
Здесь реализованы два элемента управления для отображения чисел, один инициализирует CounterController, а другой используется напрямую.
2. Управление зависимостями
На самом деле управление зависимостями GetX использовалось в предыдущем разделе.После инициализации контроллера в GetBuilder его можно использовать в другом месте.Get.find()
Найдите соответствующий контроллер, который является управлением зависимостями GetX. GetX Dependency Manager может внедрять экземпляры любого типа и предоставляет несколько способов вставки/регистрации зависимостей.
Вставить/зарегистрировать зависимости
Get.put
использоватьput
Вставьте зависимые объекты в GetX:
Get.put<CounterController>(CounterController());
Get.put<CounterController>(CounterController(), permanent: true);
Get.put<CounterController>(CounterController, tag: "counter");
При вставке зависимости можно задать дополнительные параметры помимо экземпляра зависимого класса:
- permanent: независимо от того, является ли он постоянным, значение по умолчанию false уничтожит экземпляр, когда он больше не используется, а значение true сохранит его навсегда.
- tag: Метка, используемая для различения разных экземпляров одного и того же класса.
Get.lazyPut
Ленивая инициализация означает, что объекты экземпляра инициализируются только тогда, когда они необходимы, то есть при первом обнаружении класса.
///只有当第一次使用Get.find<CounterController>时,CounterController才会被调用。
Get.lazyPut<CounterController>(() => CounterController());
Get.lazyPut<CounterController>(
() {
// ... some logic if needed
return CounterController();
},
tag: Math.random().toString(),
fenix: true
)
У lazyPut также есть дополнительные параметры, в основном такие же, как и у put.
-
fenix: аналогично «постоянному», за исключением того, что экземпляр отбрасывается, когда он не используется, но воссоздается, когда он снова нужен.
-
tag: Метка, используемая для различения разных экземпляров одного и того же класса.
Get.putAsync
putAsync
Экземпляр может быть зарегистрирован асинхронно. Используется, когда некоторые экземпляры необходимо инициализировать асинхронно, напримерSharedPreferences
:
Get.putAsync<SharedPreferences>(() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', 12345);
return prefs;
});
Как положить, также имеетpermanent
а такжеtag
параметры, а эффект тот же.
Get.create
create
а такжеput
Использование в основном аналогично, разница заключается в егоpermanent
По умолчанию истинно.
Get.create<CounterController>(() => CounterController());
использовать
пройти черезfind()
Метод получает экземпляр зависимости:
final controller = Get.find<CounterController>();
// 或者
CounterController controller = Get.find();
///通过 tag 获取
final controller = Get.find<CounterController>("counter");
также черезdelete()
метод для ручного удаления внедренного экземпляра зависимости. В большинстве случаев вам не нужно вызывать этот метод вручную. GetX автоматически обработает его внутри и удалит автоматически, когда он не нужен.
Get.delete<CounterController>();
3. Управление маршрутизацией
Маршрутизация также является важной частью проекта Flutter.Переход между страницами во Flutter достигается за счет маршрутизации.GetX предоставляет普通路由
а также别名路由
.
нормальный маршрут
-
to
: войти в следующий интерфейс
Get.to(CounterPage());
использоватьarguments
Для передачи параметров:
Get.to(CounterPage(), arguments: count);
использоватьarguments
Метод может передавать параметры любого типа.
Получите параметры на следующей странице:
dynamic args = Get.arguments;
-
off
: Вход в следующий интерфейс, и навигация не возвращается
Get.off(CounterPage());
-
offAll
: Перейти к следующему интерфейсу и отменить все предыдущие маршруты
Get.offAll(CounterPage());
-
back
:вернуть
Get.back();
Возвращаемый параметр:
Get.back(result: 'success');
Получите возвращаемый параметр:
var data = await Get.to(CounterPage());
псевдоним маршрутизации
Сначала создайтеRouteGet
(имя определяется само собой) класс, который используется для унифицированной настройки отношения отображения маршрутизации:
class RouteGet {
/// page name
static const String counter = "/counter";
///pages map
static final List<GetPage> getPages = [
GetPage(
name: counter,
page: () => CounterPage(),
)
];
}
GetPage
Определите отношение сопоставления между псевдонимами и страницами.
затем вGetMaterialApp
провестиinitialRoute
а такжеgetPages
Конфигурация начальной страницы и коллекции карт маршрутов:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
initialRoute: RouteGet.counter,
getPages: RouteGet.getPages,
theme: ThemeData(
primarySwatch: Colors.blue,
)
);
}
}
Переход и передача параметров
Способ использования в основном такой же, как и у обычной маршрутизации, но способов больше.Named
- Прыжок по маршруту:
Get.toNamed(RouteGet.login);
- Параметры маршрутизации:
Get.toNamed(RouteGet.login, arguments: {"name":"aaaa"});
Вы также можете напрямую следовать псевдониму маршрута с параметрами, аналогично тому, как URL получает параметры передачи:
Get.toNamed("/NextScreen?device=phone&id=354&name=Enzo");
-
Получить параметры:
пройти через
arguments
Передайте параметры, получите параметры на следующей странице и используйте их напрямуюGet.arguments
Получить переданные параметры:
dynamic args = Get.arguments;
Как URL передает параметры после использования псевдонима, используйтеGet.parameters
Параметры приобретения:
Get.parameters['device']
Bindings
Bindings
В основном используется совместно с роутингом, при входе на страницу через GetX роутинг будет вызываться автоматическиdependencies
метод, где вы можете зарегистрировать зависимости и т. д.
class CounterBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<CounterController>(() => CounterController());
Get.put<Service>(()=> Api());
}
}
Обычное использование маршрутизации:
Get.to(CounterPage(), binding: CounterBinding());
Используется псевдонимная маршрутизация, вGetPage
Установите маршрут, соответствующийBindings
///pages map
static final List<GetPage> getPages = [
GetPage(
name: counter,
page: () => CounterPage(),
binding: CounterBinding() ///设置Binding
)
];
Тогда способ использования альтернативной маршрутизации не изменится.
Дополнительные сведения об операциях, связанных с маршрутизацией, см. в официальной документации:route_management
На данный момент интеграция и основные функции GetX: управление состоянием, управление зависимостями и управление маршрутизацией реализованы, и можно начинать разработку проекта.
4. Использование плагина GetX
Чтобы удобно использовать GetX в проекте, вы можете установить подключаемый модуль GetX. Используя GetX, вы можете быстро создавать шаблоны страниц GetX, а также быстро использовать функции, связанные с GetX, с помощью сочетаний клавиш. Плагин показан на рисунке:
директория после установки右键 -> New
Появится меню GetX, выберитеGetX
Во всплывающем интерфейсе можно быстро создать шаблон страницы, плагин используется как показано на рисунке:
После нажатия OK он будет сгенерирован в соответствующем каталогеbinding
,controller
,state
,view
Четыре файла, как показано ниже:
Имя файла можно задать в настройках плагина.
Соответствующее содержимое файла выглядит следующим образом:
- **binding:** используется для ленивой загрузки соответствующего контроллера
class CounterBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => CounterController());
}
}
- controller:Написать код бизнес-логики интерфейса, включая функции обратного вызова жизненного цикла
class CounterController extends GetxController {
final CounterState state = CounterState();
@override
void onReady() {
// TODO: implement onReady
super.onReady();
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
}
- state:Хранить данные о состоянии интерфейса
class CounterState {
CounterState() {
///Initialize variables
}
}
- view:Элементы управления интерфейсом, в основном для разработки интерфейса
class CounterPage extends StatelessWidget {
final controller = Get.find<CounterController>();
final state = Get.find<CounterController>().state;
@override
Widget build(BuildContext context) {
return Container();
}
}
используется здесьBindings
метод, он автоматически зарегистрирует контроллер в привязке и сгенерирует код контроллера поиска на странице.
Кроме того, здесь используется состояние, так что, когда на странице слишком много данных о состоянии, все данные о состоянии можно извлечь отдельно и поместить в состояние. Это более удобно для обслуживания и позволяет избежать чрезмерного раздувания контроллера.
Для получения дополнительной информации об использовании плагина GetX, пожалуйста, обратитесь к вводной статье автора плагина:Плагин IDEA для генерации кода GetX, супер подробное объяснение функций (видите суть через явление)
5. Интернационализация
GetX обеспечивает обработку многоязычной интернационализации, что удобно для многоязычного управления и переключения в проекте.
- Сначала создайте класс языковых ресурсов, наследуемый от класса GetX.
Translations
, выполнитьget keys
:
class StringRes extends Translations{
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': {
'hello': '你好 世界'
},
'en_US':{
'hello': 'Hello World'
}
};
}
Возвращает многоязычную конфигурацию по ключам,key
идентификатор языка, формат[国家]_[语言]
, value — это карта, в которой хранятся наши фактические текстовые ресурсы.
- затем в
GetMaterialApp
настроить в:
GetMaterialApp(
translations: StringRes(),
locale: const Locale('zh', 'CN'),
fallbackLocale: Locale('en', 'US')
...
);
translations
Входящий - это то, что мы определяем для наследования отTranslations
объект класса,locale
наш язык по умолчанию,fallbackLocale
Это ресурс, настроенный fallbackLocale, когда наш языковой ресурс по умолчанию недоступен.
locale
Вы также можете получить языковой стандарт системы, используя:
import 'dart:ui' as ui;
return GetMaterialApp(
locale: ui.window.locale,
);
- использовать
При использовании используйте соответствующие ресурсы напрямуюkey.str
Вы можете следующим образом:
Text('hello'.tr);
- изменить язык
использоватьGet.updateLocale
изменить язык:
Get.updateLocale(const Locale('en', 'US'));
оптимизация
После приведенной выше конфигурации проект реализовал несколько языков и может быть переключен, но обнаружено, что если все языки записаны в один файл, контент становится слишком большим для управления, поэтому соответствующие языковые ресурсы можно разделить. ., по одному файлу на каждый язык:
str_res_zh.dart:
const zh_CN_res = {
'hello': '你好 世界',
};
str_res_en:
const en_US_res = {
'hello': 'Hello World',
};
Затем StringRes модифицируется следующим образом:
class StringRes extends Translations{
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': zh_CN_res,
'en_US':en_US_res
};
}
Это облегчает управление. Но есть еще проблема, при использовании нужно использовать каждый раз'hello'.tr
, этот ручной метод очень недружественный, нет подсказки и может быть неправильно, поэтому можно дополнительно оптимизировать, как и при использовании String ресурсов в Android, определить специальный класс для хранения строковых ключей:
str_res_keys.dart
class SR{
static const hello = 'hello';
}
Измените конфигурацию языка и текстовых ресурсов следующим образом:
const zh_CN_res = {
SR.hello: '你好 世界',
};
const en_US_res = {
SR.hello: 'Hello World',
};
Затем используйте следующим образом:
Text(SR.hello.tr);
Таким образом, многоязычная конфигурация проекта завершена.Общая директория выглядит так, как показано на рисунке:
6. Другие функции GetX
snackbar
GetX обеспечивает удобное и быстрое использованиеsnackbar
метод, используйте следующее:
Get.snackbar("title", "message");
По умолчанию всплывает вверху, вы можете использоватьsnackPosition
Измените местоположение всплывающего окна, эффект будет следующим:
В дополнение к положению вы также можете установить множество свойств, таких как цвет текста, цвет фона и т. д. Подробные свойства, которые можно установить, следующие:
String title,
String message, {
Color? colorText,
Duration? duration = const Duration(seconds: 3),
/// with instantInit = false you can put snackbar on initState
bool instantInit = true,
SnackPosition? snackPosition,
Widget? titleText,
Widget? messageText,
Widget? icon,
bool? shouldIconPulse,
double? maxWidth,
EdgeInsets? margin,
EdgeInsets? padding,
double? borderRadius,
Color? borderColor,
double? borderWidth,
Color? backgroundColor,
Color? leftBarIndicatorColor,
List<BoxShadow>? boxShadows,
Gradient? backgroundGradient,
TextButton? mainButton,
OnTap? onTap,
bool? isDismissible,
bool? showProgressIndicator,
DismissDirection? dismissDirection,
AnimationController? progressIndicatorController,
Color? progressIndicatorBackgroundColor,
Animation<Color>? progressIndicatorValueColor,
SnackStyle? snackStyle,
Curve? forwardAnimationCurve,
Curve? reverseAnimationCurve,
Duration? animationDuration,
double? barBlur,
double? overlayBlur,
SnackbarStatusCallback? snackbarStatus,
Color? overlayColor,
Form? userInputForm,
}
Вы можете установить его в соответствии с вашими потребностями.
dialog
GetX предоставляет ярлык для использования диалогового окна и предоставляет два способа: первый — отобразить виджет, отображаемый диалоговым окном, а второй — использовать стиль диалогового окна по умолчанию, предоставленный GetX для отображения:
Первый:
Get.dialog(Widget)
Второй:
Get.defaultDialog(title: "title", middleText: "this is dialog message");
Эффект:
В дополнение к title и middleText вы также можете установить кнопки OK и Cancel, а также соответствующие параметры обратного вызова, закругленные углы, цвет фона и другие параметры.
Future<T?> defaultDialog<T>({
String title = "Alert",
EdgeInsetsGeometry? titlePadding,
TextStyle? titleStyle,
Widget? content,
EdgeInsetsGeometry? contentPadding,
VoidCallback? onConfirm,
VoidCallback? onCancel,
VoidCallback? onCustom,
Color? cancelTextColor,
Color? confirmTextColor,
String? textConfirm,
String? textCancel,
String? textCustom,
Widget? confirm,
Widget? cancel,
Widget? custom,
Color? backgroundColor,
bool barrierDismissible = true,
Color? buttonColor,
String middleText = "Dialog made in 3 lines of code",
TextStyle? middleTextStyle,
double radius = 20.0,
// ThemeData themeData,
List<Widget>? actions,
// onWillPop Scope
WillPopCallback? onWillPop,
// the navigator used to push the dialog
GlobalKey<NavigatorState>? navigatorKey,
})
bottomSheet
Используйте следующим образом:
Get.bottomSheet(Container(
height: 200,
color: Colors.white,
child: const Center(
child: Text("bottomSheet"),
),
));
Эффект:
При ближайшем рассмотрении выясняется, что либоsnackbar
,dialog
ещеbottomSheet
Ни один из них не требует контекста, что означает, что его можно вызывать из любого места проекта.
Если вы хотите отменитьsnackbar
,dialog
,bottomSheet
можно использоватьGet.back()
.
GetUtils
GetX также предоставляет множество инструментальных методов, которые вы можете использоватьGetUtils
Вызовы, такие как оценка того, является ли это почтовым ящиком, оценка типа формата файла и т. д., см. следующий рисунок для получения подробной информации:
Кроме того, GetX также предоставляет некоторые методы расширения:
//检查应用程序在哪个平台上运行。
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//检查设备类型
GetPlatform.isMobile
GetPlatform.isDesktop
//所有平台都是独立支持web的!
//你可以知道你是否在浏览器内运行。
//在Windows、iOS、OSX、Android等系统上。
GetPlatform.isWeb
// 相当于.MediaQuery.of(context).size.height,
//但不可改变。
Get.height
Get.width
// 提供当前上下文。
Get.context
// 在你的代码中的任何地方,在前台提供 snackbar/dialog/bottomsheet 的上下文。
Get.contextOverlay
// 注意:以下方法是对上下文的扩展。
// 因为在你的UI的任何地方都可以访问上下文,你可以在UI代码的任何地方使用它。
// 如果你需要一个可改变的高度/宽度(如桌面或浏览器窗口可以缩放),你将需要使用上下文。
context.width
context.height
// 让您可以定义一半的页面、三分之一的页面等。
// 对响应式应用很有用。
// 参数: dividedBy (double) 可选 - 默认值:1
// 参数: reducedBy (double) 可选 - 默认值:0。
context.heightTransformer()
context.widthTransformer()
/// 类似于 MediaQuery.of(context).size。
context.mediaQuerySize()
/// 类似于 MediaQuery.of(context).padding。
context.mediaQueryPadding()
/// 类似于 MediaQuery.of(context).viewPadding。
context.mediaQueryViewPadding()
/// 类似于 MediaQuery.of(context).viewInsets。
context.mediaQueryViewInsets()
/// 类似于 MediaQuery.of(context).orientation;
context.orientation()
///检查设备是否处于横向模式
context.isLandscape()
///检查设备是否处于纵向模式。
context.isPortrait()
///类似于MediaQuery.of(context).devicePixelRatio。
context.devicePixelRatio()
///类似于MediaQuery.of(context).textScaleFactor。
context.textScaleFactor()
///查询设备最短边。
context.mediaQueryShortestSide()
///如果宽度大于800,则为真。
context.showNavbar()
///如果最短边小于600p,则为真。
context.isPhone()
///如果最短边大于600p,则为真。
context.isSmallTablet()
///如果最短边大于720p,则为真。
context.isLargeTablet()
///如果当前设备是平板电脑,则为真
context.isTablet()
///根据页面大小返回一个值<T>。
///可以给值为:
///watch:如果最短边小于300
///mobile:如果最短边小于600
///tablet:如果最短边(shortestSide)小于1200
///desktop:如果宽度大于1200
context.responsiveValue<T>()
Исходный код:flutter_app_core
Для получения дополнительной информации, пожалуйста, обратитесь к официальной документации:GetX
Использованная литература:
Цикл статей о построении фреймворка приложения Flutter:
- Создание инфраструктуры приложения Flutter (1) Интеграция с GetX и подробное объяснение использования
- Создание фреймворка приложения Flutter (2) адаптация экрана
- Создание инфраструктуры приложения Flutter (3) Анализ данных Json
- Создание инфраструктуры приложения Flutter (4) Инкапсуляция сетевых запросов