Rafa Ruiz

Merge branch 'j_master'

Too many changes to show.

To preserve performance only 14 of 14+ files are displayed.

No preview for this file type
*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.*
Every PR must update the corresponding documentation in the `code`, and also the readme in english with the following changes.
## Pre-launch Checklist
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making or feature I am adding, or @jonataslaw said the PR is test-exempt.
- [ ] All existing and new tests are passing.
... ...
... ... @@ -18,12 +18,12 @@ jobs:
steps:
# The branch or tag ref that triggered the workflow will be checked out.
# https://github.com/actions/checkout
- uses: actions/checkout@v1
- uses: actions/checkout@v3
# Setup a flutter environment.
# https://github.com/marketplace/actions/flutter-action
- uses: subosito/flutter-action@v1
- uses: subosito/flutter-action@v2
with:
flutter-version: "2.0.2"
flutter-version: "3.0.5"
channel: "stable"
- run: flutter pub get
#- run: flutter analyze
... ...
... ... @@ -80,3 +80,6 @@ example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig
example/macos/Flutter/ephemeral/
example/macos/Flutter/GeneratedPluginRegistrant.swift
# Coverage files
coverage/
\ No newline at end of file
... ...
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "getx",
"request": "launch",
"type": "dart"
},
{
"name": "example",
"cwd": "example",
"request": "launch",
"type": "dart"
},
{
"name": "example_nav2",
"cwd": "example_nav2",
"request": "launch",
"type": "dart"
},
{
"name": "example_nav2 WEB",
"cwd": "example_nav2",
"request": "launch",
"type": "dart",
"deviceId": "Chrome"
}
]
}
\ No newline at end of file
... ...
{
"cSpell.enableFiletypes": ["!markdown"]
}
... ...
## [4.6.1]
Fix GetConnect on Flutter web
## [4.6.0]
Add useInheritedMediaQuery to GetMaterialApp and GetCupertinoApp (@davidhole)
Add Circular reveal Transition (@parmarravi)
Add request to failed response (@heftekharm)
Fix internationalization with only country code (@codercengiz)
Add GetTickerProviderStateMixin when multiple AnimationController objects are used (@NatsuOnFire)
Add the followRedirects and maxRedirects fields to the Request object (@wei53881)
Fix to rx.trigger fires twice (@gslender)
Add proxy setting support to GetConnect (@jtans)
Fix markAsDirty used on permanent controllers (@zenalex)
Update Korean readme (@dumbokim)
## [4.5.1]
Fix Snackbar when it have action and icon the same time
## [4.5.0] - Big Update
To have a page-agnostic snackbar, we used OverlayRoute to display a partial route.
However this had several problems:
1: There was no possibility to close the page without closing the snackbar
2: Get.back() could cause problems with tests of Get.isSnackbarOpen not being properly invoked
3: Sometimes when using iOS popGesture with an open snackbar, some visual inconsistency might appear.
4: When going to another route, the snackbar was not displayed on the new page, and if the user clicked on the new route as soon as he received a Snackbar, he could not read it.
We remade the Snackbar from scratch, having its Api based on Overlay, and now opening a Snackbar won't be tied to a route, you can normally navigate routes while a Snackbar is shown at the top (or bottom), and even the PopGesture of the iOS is not influenced by it.
Using Get.back() is handy, it's a small command, which closes routes, dialogs, snackbars, bottomsheets, etc, however Getx 5 will prioritize code safety, and splitting will reduce the check code as well. Currently we have to check if a snackbar is open, to close the snackbar and prevent the app from going back a page, all this boilerplate code will be removed, at the cost of having what it closes in front of Get.back command.
For backwards compatibility, Get.back() still works for closing routes and overlays, however two new commands have been added: Get.closeCurrentSnackbar() and Get.closeAllSnackbars().
Maybe we will have a clearer api in GetX 5, and maybe Get.back() will continue to do everything like it does today. The community will be consulted about the desired api. However version 5 will definitely have commands like: Get.closeCurrentSnackbar, Get.closeCurrentDialog etc. There is also the possibility to close a specific snackbar using the return of Get.snackbar, which will no longer return a void, and now return a SnackbarController.
Snackbars now also have a Queue, and no longer stack one on top of the other, preventing viewing. GetX now has flexible, customizable, route-independent, and completely stable Snackbars.
Fixed bugs where the snackbar showed an error in debug mode for a fraction of a second. We found that Flutter has a bug with blur below 0.001, so we set the minimum overlayBlur value to this value if it is ==true.
Errors with internationalization were also fixed, where if you are in UK, and the app had the en_US language, you didn't have American English by default. Now, if the country code is not present, it will automatically fetch the language code before fetching a fallbackLanguage.
Update locale also now returns a Future, allowing you to perform an action only when the language has already changed (@MHosssam)
We are very happy to announce that GetX is now documented in Japanese as well, thanks to (@toshi-kuji)
GetX has always been focused on transparency. You can tell what's going on with your app just by reading the logs on the console. However, these logs shouldn't appear in production, so it now only appears in debug mode (@maxzod)
@maxzod has also started translating the docs into Arabic, we hope the documentation will be complete soon.
Some remaining package logs have been moved to Get.log (@gairick-saha)
RxList.removeWhere received performance optimizations (@zuvola)
Optimizations in GetConnect and added the ability to modify all request items in GetConnect (@rodrigorahman)
The current route could be inconsistent if a dialog were opened after a transition, fixed by @xiangzy1
Fixed try/catch case missed in socket_notifier (@ShookLyngs)
Also we had fixes in the docs: @DeathGun3344 @pinguluk
GetX also surpassed the incredible mark of more than 7000 likes, being the most liked package in all pub.dev, went from 99% to 100% popularity, and has more than 5.3k stars on github. Documentation is now available in 12 languages, and we're happy for all the engagement from your community.
This update is a preparation update for version 5, which will be released later this year.
Breaking and Depreciation:
GetBar is now deprecated, use GetSnackbar instead.
dismissDirection now gets a DismissDirection, making the Snackbar more customizable.
## [4.3.8]
- Fix nav2 toNamed remove the route
## [4.3.7]
- Fix wrong currentRoute when a route is removed
- Remove take that limits the router outlet depth (@steven-spiel)
## [4.3.6]
- Fix error with autodispose of additional dependencies beyond GetxController
- Added ability to add your own delegate to RouterOutlet (@steven-spiel)
- Added listenAndPump to Rx to give Rx the same behavior as BehaviorSubject (@steven-spiel)
## [4.3.5]
- Fix GetConnect timeout (@jasonlaw)
- Improve Vietnamese docs (@hp1909)
- Refactor placeholder name route to unnamed routes (@roipeker).
- Fix: Navigate to a page identical to Get.offNamed.
- Fix: Wrong nameRoute after a route is removed
- Added assert to prevent the user from starting a route name without slash.
## [4.3.4]
- Improve docs
## [4.3.3]
- Fix Get.reset
## [4.3.2]
- Fix nullable on internacionalization (@jmguillens)
- Fix nullable on Rx.stream (@steven-spiel)
## [4.3.1]
- Fix controller is not removed when keyboard is open.
- Improved: Safe removal and insertion of controllers.
## [4.3.0]
- Added GetResponsiveWidget (@ahmednfwela)
- Added `Get.replace()` (@jwelmac)
- Added Improve korean doc (@sejun2)
- Fix multiple middlewares redirect (@liasica)
- Added gestureWidth and showCupertinoParallax to GetPage to customize cupertino transitions
## [4.2.5]
- Added anchorRoute and filterPages to GetRouterOutlet (@ahmednfwela)
- Added scrollBehavior and scaffoldMessengerKey to GetMaterialapp(@ejabu and @alionour)
- Fix error when child on MaterialApp is null (@ahmednfwela)
- Fix Korean docs (@rws08)
- Fix error with onClose called before routeTransition on Get.offNamed
## [4.2.4]
- Fix Get.offAll removing GetxServices from memory
## [4.2.3]
- Fix back button on navigator 2
- Added parameters and arguments to Get.rootDelegate
## [4.2.1]
- Remove [] from docs to try fix pub score
## [4.2.0] - Big update
This update fixes important bugs as well as integrates with Navigator 2. It also adds GetRouterOutlet, similar to angular RouterOutlet thanks to @ahmednfwela. Also, the documentation translation for Vietnamese (@khangahs) has been added, making the GetX documentation available for 11 different languages, which is just fantastic for any opensource project. GetX has achieved more than 5.4k likes from the pub, and more than 4k stars on github, has videos about it with 48k on youtube, and has communities in the 4 hemispheres of the earth, besides having a large list of contributors as you see bellow. We're all happy to facilitate development with dart and flutter, and that making programming hassle-free has been taken around the world.
Changes in this version:
- Fix: Navigating to the same page with Get.offNamed does not delete the controller from that page using Get.lazyPut.
- Fix Readme GetMiddleware typos
by @nivisi
- Fix url replace error
by @KevinZhang19870314
- Changed response default encoding from latin1 to utf8
by @heftekharm
- Add Duration in ExtensionBottomSheet
by @chanonpingpong
- Added compatibility with dart-lang/mockito
by @lifez
- Added extensions methods to convert value in percent value
by @kauemurakami
- Set darkTheme equal theme when darkTheme is null
by @eduardoFlorence
- Add padding to 'defaultDialog'
by @KevinZhang19870314
- GraphQLResponse inherit Response info
by @jasonlaw
- Fix Redundant concatenating base url
by @jasonlaw
- Add content type and length into the headers when the content type is 'application/x-www-form-urlencoded'
by @calvingit
- Make withCredentials configurable
by @jasonlaw
- Fix flutter 2.0 error
by @yunchiri
- Allow deleting all registered instances
by @lemps
- Refactor/rx interface notify children
@by kranfix
- Fixed parameter parsing and middleware sorting
by @ahmednfwela
- Improvements to router outlet
by @ahmednfwela
- Minor improvements and bug fixes
by @ahmednfwela
- Adding route guards and improving navigation
by @ahmednfwela
- Fix RxInterface.proxy losing its previous value on exception
by @WillowWisp
- Added dispose() for bottomSheet.
by @furkankurt
- Added Pull request template
by @unacorbatanegra
- Fix and update documentation:
@Farid566,
@galaxykhh,
@arslee07,
@GoStaRoff,
@BondarenkoArtur,
@denisrudnei,
@Charly6596,
@nateshmbhat,
@hrithikrtiwari,
@Undeadlol1,
@rws08,
@inuyashaaa,
@broccolism,
@aadarshadhakalg,
@ZeroMinJeon
## [4.1.4]
- Adjust operator + and - to RxInt (@eduardoflorence)
- Fix dark theme (@eduardoflorence)
- Fix form-urlencoded on GetConnect (@aramayyes)
## [4.1.3]
- Fix "Error: A value of type 'Locale?' can't be returned from a function"on flutter web (@nickwri)
- Fix plural translations to expressions >1 (@WolfVic)
## [4.1.2]
- Fix warning ˜can add data to a closed stream˜ when GetBuilder and Obx are nested
- Fix get_connect decoder can not be null (@Goddchen)
- Migrate example code (@3lB4rt0)
- Fix initial value of nullables (@RafaRuiz)
- Improve error message to navigation (@maxzod)
- Fix typo on docs (@Rahulshahare)
- Fixed darktheme being changed only through Get.changeTheme and not through the DarkTheme theme property in MaterialApp (@GoldenSoju)
- Fix controller is removed when navigate to same page (@eduardoflorence)
- Fix missing reload() and reloadAll() to Get extensions (@lkloon123)
## [4.1.1]
- Remove mandatory initialValue to nullables types
## [4.1.0]
- Added Rxn to non nullables reactives types
## [4.0.3]
- Added new linter rules to improve score
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)
[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
<a href="https://github.com/Solido/awesome-flutter">
<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" />
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
<div align="center">
**Languages:**
[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)
[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)
[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)
[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)
[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)
[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)
[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)
[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)
[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)
[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
[![العربيه](https://img.shields.io/badge/Language-arabic-blueviolet?style=for-the-badge)](README-ar.md)
</div>
<div dir="rtl">
- [عن المكتبة](#عن-المكتبة)
- [التركيب](#التركيب)
- [بناء تطبيق العداد 🔢](#بناء-تطبيق-العداد-)
- [The Three pillars](#the-three-pillars)
- [State management](#state-management)
- [Reactive State Manager](#reactive-state-manager)
- [More details about state management](#more-details-about-state-management)
- [Route management](#route-management)
- [More details about route management](#more-details-about-route-management)
- [Dependency management](#dependency-management)
- [More details about dependency management](#more-details-about-dependency-management)
- [Utils](#utils)
- [Internationalization](#internationalization)
- [Translations](#translations)
- [Using translations](#using-translations)
- [Using translation with singular and plural](#using-translation-with-singular-and-plural)
- [Using translation with parameters](#using-translation-with-parameters)
- [Locales](#locales)
- [Change locale](#change-locale)
- [System locale](#system-locale)
- [Change Theme](#change-theme)
- [GetConnect](#getconnect)
- [Default configuration](#default-configuration)
- [Custom configuration](#custom-configuration)
- [GetPage Middleware](#getpage-middleware)
- [Priority](#priority)
- [Redirect](#redirect)
- [onPageCalled](#onpagecalled)
- [OnBindingsStart](#onbindingsstart)
- [OnPageBuildStart](#onpagebuildstart)
- [OnPageBuilt](#onpagebuilt)
- [OnPageDispose](#onpagedispose)
- [Other Advanced APIs](#other-advanced-apis)
- [Optional Global Settings and Manual configurations](#optional-global-settings-and-manual-configurations)
- [Local State Widgets](#local-state-widgets)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [Useful tips](#useful-tips)
- [StateMixin](#statemixin)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [How to use it](#how-to-use-it)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [Tests](#tests)
- [Tips](#tips)
- [Mockito or mocktail](#mockito-or-mocktail)
- [Using Get.reset()](#using-getreset)
- [Get.testMode](#gettestmode)
- [Breaking changes from 2.0](#breaking-changes-from-20)
- [Why Getx?](#why-getx)
- [Community](#community)
- [Community channels](#community-channels)
- [How to contribute](#how-to-contribute)
- [Articles and videos](#articles-and-videos)
# عن المكتبة
- `GetX` مكتبه خفيفه وقوية لفلاتر , توفر المكتبه السرعه العاليه في التحكم في الحاله , نظام حقن `Ddependency injection` ذكي , والتحكم في التنقل بين الصفحات بسرعه وسهوله
- `GetX`
- تعتمد علي 3 نقاط اساسية . **الانتاجية والسرعه والتنظيم**
- **السرعه:** `GetX` تركز علي السرعه واقل استخدام للموارد,`GetX` لا تستخدم `Streams` او `ChangeNotifier`.
- **الانتاجية:** `GetX` تستخدم طريقه سهله ومريحة في كتابة الكود , لا يهم ماذا تريد انت تبني , يوجد دائما طريقه اسهل لبناء باستخدام `GetX` , ستوفر ساعات من العمل وتوفر لك اعلي سرعه يمكن الوصل لها في تطبيقاتك عموما , يجب ان يهتم المطور بالتخلص من الموارد الغير مستخدمه من الذاكرة , مع `GetX` هذا غير ضروري لانه يتم التخلص من الموارد الغير مستخدمه من الذاكره تلقائيا, اذا اردت تركهم دائما في الذاكرة يمكنك ذلك لكن يجب عليك ان تستخدم `permanent: true` بالاضافه الي توفير الوقت تم تقليل امكانية ترك الموارد في الذاكره بدون التخلص منها , يتم حقن الموارد `lazy` افتراضيا
- **التنظيم:** `GetX` تسمح لك بفصل الـ `view` عن الـ `presentation logic` و `business logic` باكامل,
بالنسبة للحقن `dependency injection` و التنقل بين الشاشات لا تحتاج فيهم `context` للتنقل بين الصفحات , ولا تحتاك `context` للوصول للموارد عن طريق widget tree, لذلك يتم الفصل بالكامل بين `presentation logic` و `business logic` لا تحتاج لحقن ال `Controllers/Models/Blocs`
داخل شجره العناصر `Widget Tree` خلال `MultiProvider`s.
لان , `GetX` تستخدم نظام حقن خاص بها ويمكنك من فصل الـ `DI` عن الوجهات بالكامل .
- مع `Getx` تعرف ايه يكون الكود الخاص ب كل جزء في التطبيق , تساعدك في كتابة كود نظيف , بالاضافه الي سهوله التطوير مستقبلا , وهذا يمكنك من مشاركه الاجزاء `modules` امر صعب ليصبح سهل جدا .
`BLOC` كان نقطه البداية لهذا الامر وتظيم الكود بهذه الطريقه في فلاتر , عن طريق فصل كود البزنس عن الواجهات , `GetX` هي التطور لذلك الامر , وذلك عن طريق الاضافه الي ذلك فصل حقن الموارد وفصل التنقل بين الشاشات ايضا , وطبقه البيانات بالكامل ايضا , تعلم اين يكون كل شي في المشروع
- `Getx` توفر لك السهوله في بناء المشروع والاستقرار كلما كبر حجم المشروع واقصي سرعه ممكن , توفر لك ايضا نظام كامل يعمل في تجانس تام , سهل للمبتدئين , ومنظم للخبراء , امن , مستقر , ومحدث باستمرار ويوفر لك موجموعه من الادوات لتسهل عليك
- `GetX` ليست ضخمه , تمتلك المكتبة العديد من المميزات تجعلك تبدا في البرمجه بدون القلق عن اي شي كل ميزه منهم منقسمه عن الاخري ولا يبداو الا عندما تستخدمهم , اذا استخدمت جزء التحكم في الحاله فقط لن يتم استخدام جزء التنقل بين الشاشات في تطبيقك الا `Compiled` والعكس صحيح ! .
-`Getx` لديها نظام شامل , ومجتمع كبير , وعداد كبير من المطورين , وسوف يتم تحديثها باستمرار , تعمل المكتبة علي كل الانظمه بنفس الكود دون تغيير `Android`, `iOS`, `Web`, `Mac`, `Linux`, `Windows` حتي علي الخادم يمكنك استخدام `Getx` لبناء تطبيقات الويب
**[Get Server](https://github.com/jonataslaw/get_server)**.
**بالاضافه الي ذلك يمكن محاكاه الامر اكثر في فلاتر والخادم عن طريق [Get CLI](https://github.com/jonataslaw/get_cli)**.
**وللمزيد من الانتاجية يمكنك استخدام اضافه للـ**
- [فيجوال ستوديو كود](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)
- [اندرويد استوديو و انتلج](https://plugins.jetbrains.com/plugin/14975-getx-snippets)
# التركيب
استخدم المكتبة في ملف `pubspec.yaml`
<div dir="ltr" >
```yaml
dependencies:
get:
```
</div>
استدعي المكتبة في الملفات الي ستستخدمها
<div dir="ltr" >
```dart
import 'package:get/get.dart';
```
</div>
# بناء تطبيق العداد 🔢
تطبيق العداد الذي يتم انشاء مع كل مشروع جديد يتعدي ال 100 سطر (بالتعليقات) ولكي اريك مدي قوه `GetX`
ساوضح لك كيفيه بناء التطبيق مع تغير قيمه العداد مع كل ضغطه زر والتقل بين الشاشات ومشاركه الحاله كل ذلك بطريقه منذمه وفصل تام لكود البزنس عن الواجهات فقط ب 26 سطر من ضمنهم التعليقات 🔥
- الخطوه الاولي :
اكتب `Get` امام `MaterialApp` لتصبح `GetMaterialApp`
<div dir="ltr" >
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
</div>
- ملحوظه : هذا لا يعتبر تعديل علي `MaterialApp` لان , `GetMaterialApp` عباره عن عنصر معد مسبقا ويستخدم `MaterialApp` تحت الغطاء , يمكن تغير الاعدادات يدوين لكن هذا غير ضروري لان ``سيقوم بعمل المسارات و حقن العناصر والترجمه وكل شي تحتاجه ولكن اذا كنت تنوي لاستخدام المكتبة فقط للتحكم في الحاله`State managment`فهذه الخطوه غير ضرورية تكون هذه الخطوه ضرورية عندما تريد التنقل بين الشاشات او عرض`snackbars`والترجمه و اي شي يعتمد علي`context`وتقوم`getx` بتوفيره
- الخطوه الثانية
قم بكتابة الكود داخل `class` وكتابة المتغيرات والدوال , يمكنك جعل المتغير قابلع لاعاده بناء الواجها عند تغير قيمته باستخدام ال `getter` `.obs` .
<div dir="ltr" >
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
</div>
- الخطوه الثالثه
ابني الواجهه واستخدم `StatelessWidget` لتوفير الموارد , مع `Getx` يمكنك الاستغناء عن `StatefulWidget`.
<div dir="ltr" >
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Instantiate your class using Get.put() to make it available for all "child" routes there.
final c = Get.put(Controller());
return Scaffold(
// Use Obx(()=> to update Text() whenever count is changed.
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// You can ask Get to find a Controller that is being used by another page and redirect you to it.
final Controller c = Get.find();
@override
Widget build(context){
// Access the updated count variable
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
</div>
Result:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
This is a simple project but it already makes clear how powerful Get is. As your project grows, this difference will become more significant.
Get was designed to work with teams, but it makes the job of an individual developer simple.
Improve your deadlines, deliver everything on time without losing performance. Get is not for everyone, but if you identified with that phrase, Get is for you!
# The Three pillars
## State management
Get has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (GetX/Obx)
### Reactive State Manager
Reactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple:
- You won't need to create StreamControllers.
- You won't need to create a StreamBuilder for each variable
- You will not need to create a class for each state.
- You will not need to create a get for an initial value.
- You will not need to use code generators
Reactive programming with Get is as easy as using setState.
Let's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.
This is your count variable:
```dart
var name = 'Jonatas Borges';
```
To make it observable, you just need to add ".obs" to the end of it:
```dart
var name = 'Jonatas Borges'.obs;
```
And in the UI, when you want to show that value and update the screen whenever the values changes, simply do this:
```dart
Obx(() => Text("${controller.name}"));
```
That's all. It's _that_ simple.
### More details about state management
**See an more in-depth explanation of state management [here](./documentation/en_US/state_management.md). There you will see more examples and also the difference between the simple state manager and the reactive state manager**
You will get a good idea of GetX power.
## Route management
If you are going to use routes/snackbars/dialogs/bottomsheets without context, GetX is excellent for you too, just see it:
Add "Get" before your MaterialApp, turning it into GetMaterialApp
```dart
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
```
Navigate to a new screen:
```dart
Get.to(NextScreen());
```
Navigate to new screen with name. See more details on named routes [here](./documentation/en_US/route_management.md#navigation-with-named-routes)
```dart
Get.toNamed('/details');
```
To close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);
```dart
Get.back();
```
To go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens, etc.)
```dart
Get.off(NextScreen());
```
To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)
```dart
Get.offAll(NextScreen());
```
Noticed that you didn't have to use context to do any of these things? That's one of the biggest advantages of using Get route management. With this, you can execute all these methods from within your controller class, without worries.
### More details about route management
**Get works with named routes and also offers lower-level control over your routes! There is in-depth documentation [here](./documentation/en_US/route_management.md)**
## Dependency management
Get has a simple and powerful dependency manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code, no Provider context, no inheritedWidget:
```dart
Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
```
- Note: If you are using Get's State Manager, pay more attention to the bindings API, which will make it easier to connect your view to your controller.
Instead of instantiating your class within the class you are using, you are instantiating it within the Get instance, which will make it available throughout your App.
So you can use your controller (or class Bloc) normally
**Tip:** Get dependency management is decoupled from other parts of the package, so if for example, your app is already using a state manager (any one, it doesn't matter), you don't need to rewrite it all, you can use this dependency injection with no problems at all
```dart
controller.fetchApi();
```
Imagine that you have navigated through numerous routes, and you need data that was left behind in your controller, you would need a state manager combined with the Provider or Get_it, correct? Not with Get. You just need to ask Get to "find" for your controller, you don't need any additional dependencies:
```dart
Controller controller = Get.find();
//Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllers instantiated, Get will always give you the right controller.
```
And then you will be able to recover your controller data that was obtained back there:
```dart
Text(controller.textFromApi);
```
### More details about dependency management
**See a more in-depth explanation of dependency management [here](./documentation/en_US/dependency_management.md)**
# Utils
## Internationalization
### Translations
Translations are kept as a simple key-value dictionary map.
To add custom translations, create a class and extend `Translations`.
```dart
import 'package:get/get.dart';
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello World',
},
'de_DE': {
'hello': 'Hallo Welt',
}
};
}
```
#### Using translations
Just append `.tr` to the specified key and it will be translated, using the current value of `Get.locale` and `Get.fallbackLocale`.
```dart
Text('title'.tr);
```
#### Using translation with singular and plural
```dart
var products = [];
Text('singularKey'.trPlural('pluralKey', products.length, Args));
```
#### Using translation with parameters
```dart
import 'package:get/get.dart';
Map<String, Map<String, String>> get keys => {
'en_US': {
'logged_in': 'logged in as @name with email @email',
},
'es_ES': {
'logged_in': 'iniciado sesión como @name con e-mail @email',
}
};
Text('logged_in'.trParams({
'name': 'Jhon',
'email': 'jhon@example.com'
}));
```
### Locales
Pass parameters to `GetMaterialApp` to define the locale and translations.
```dart
return GetMaterialApp(
translations: Messages(), // your translations
locale: Locale('en', 'US'), // translations will be displayed in that locale
fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.
);
```
#### Change locale
Call `Get.updateLocale(locale)` to update the locale. Translations then automatically use the new locale.
```dart
var locale = Locale('en', 'US');
Get.updateLocale(locale);
```
#### System locale
To read the system locale, you could use `Get.deviceLocale`.
```dart
return GetMaterialApp(
locale: Get.deviceLocale,
);
```
## Change Theme
Please do not use any higher level widget than `GetMaterialApp` in order to update it. This can trigger duplicate keys. A lot of people are used to the prehistoric approach of creating a "ThemeProvider" widget just to change the theme of your app, and this is definitely NOT necessary with **GetX™**.
You can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that:
```dart
Get.changeTheme(ThemeData.light());
```
If you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that:
- The api that checks if the dark `Theme` is being used.
- And the `Theme` Change API, you can just put this within an `onPressed`:
```dart
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
```
When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.
## GetConnect
GetConnect is an easy way to communicate from your back to your front with http or websockets
### Default configuration
You can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets.
```dart
class UserProvider extends GetConnect {
// Get request
Future<Response> getUser(int id) => get('http://youapi/users/$id');
// Post request
Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
// Post request with File
Future<Response<CasesModel>> postCases(List<int> image) {
final form = FormData({
'file': MultipartFile(image, filename: 'avatar.png'),
'otherFile': MultipartFile(image, filename: 'cover.png'),
});
return post('http://youapi/users/upload', form);
}
GetSocket userMessages() {
return socket('https://yourapi/users/socket');
}
}
```
### Custom configuration
GetConnect is highly customizable You can define base Url, as answer modifiers, as Requests modifiers, define an authenticator, and even the number of attempts in which it will try to authenticate itself, in addition to giving the possibility to define a standard decoder that will transform all your requests into your Models without any additional configuration.
```dart
class HomeProvider extends GetConnect {
@override
void onInit() {
// All request will pass to jsonEncode so CasesModel.fromJson()
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.baseUrl = 'https://api.covid19api.com';
// baseUrl = 'https://api.covid19api.com'; // It define baseUrl to
// Http and websockets if used with no [httpClient] instance
// It's will attach 'apikey' property on header from all requests
httpClient.addRequestModifier((request) {
request.headers['apikey'] = '12345678';
return request;
});
// Even if the server sends data from the country "Brazil",
// it will never be displayed to users, because you remove
// that data from the response, even before the response is delivered
httpClient.addResponseModifier<CasesModel>((request, response) {
CasesModel model = response.body;
if (model.countries.contains('Brazil')) {
model.countries.remove('Brazilll');
}
});
httpClient.addAuthenticator((request) async {
final response = await get("http://yourapi/token");
final token = response.body['token'];
// Set the header
request.headers['Authorization'] = "$token";
return request;
});
//Autenticator will be called 3 times if HttpStatus is
//HttpStatus.unauthorized
httpClient.maxAuthRetries = 3;
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
}
```
## GetPage Middleware
The GetPage has now new property that takes a list of GetMiddleWare and run them in the specific order.
**Note**: When GetPage has a Middlewares, all the children of this page will have the same middlewares automatically.
### Priority
The Order of the Middlewares to run can be set by the priority in the GetMiddleware.
```dart
final middlewares = [
GetMiddleware(priority: 2),
GetMiddleware(priority: 5),
GetMiddleware(priority: 4),
GetMiddleware(priority: -8),
];
```
those middlewares will be run in this order **-8 => 2 => 4 => 5**
### Redirect
This function will be called when the page of the called route is being searched for. It takes RouteSettings as a result to redirect to. Or give it null and there will be no redirecting.
```dart
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login')
}
```
### onPageCalled
This function will be called when this Page is called before anything created
you can use it to change something about the page or give it new page
```dart
GetPage onPageCalled(GetPage page) {
final authService = Get.find<AuthService>();
return page.copyWith(title: 'Welcome ${authService.UserName}');
}
```
### OnBindingsStart
This function will be called right before the Bindings are initialize.
Here you can change Bindings for this page.
```dart
List<Bindings> onBindingsStart(List<Bindings> bindings) {
final authService = Get.find<AuthService>();
if (authService.isAdmin) {
bindings.add(AdminBinding());
}
return bindings;
}
```
### OnPageBuildStart
This function will be called right after the Bindings are initialize.
Here you can do something after that you created the bindings and before creating the page widget.
```dart
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
print('bindings are ready');
return page;
}
```
### OnPageBuilt
This function will be called right after the GetPage.page function is called and will give you the result of the function. and take the widget that will be showed.
### OnPageDispose
This function will be called right after disposing all the related objects (Controllers, views, ...) of the page.
## Other Advanced APIs
```dart
// give the current args from currentScreen
Get.arguments
// give name of previous route
Get.previousRoute
// give the raw route to access for example, rawRoute.isFirst()
Get.rawRoute
// give access to Routing API from GetObserver
Get.routing
// check if snackbar is open
Get.isSnackbarOpen
// check if dialog is open
Get.isDialogOpen
// check if bottomsheet is open
Get.isBottomSheetOpen
// remove one route.
Get.removeRoute()
// back repeatedly until the predicate returns true.
Get.until()
// go to next route and remove all the previous routes until the predicate returns true.
Get.offUntil()
// go to next named route and remove all the previous routes until the predicate returns true.
Get.offNamedUntil()
//Check in what platform the app is running
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//Check the device type
GetPlatform.isMobile
GetPlatform.isDesktop
//All platforms are supported independently in web!
//You can tell if you are running inside a browser
//on Windows, iOS, OSX, Android, etc.
GetPlatform.isWeb
// Equivalent to : MediaQuery.of(context).size.height,
// but immutable.
Get.height
Get.width
// Gives the current context of the Navigator.
Get.context
// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.
Get.contextOverlay
// Note: the following methods are extensions on context. Since you
// have access to context in any place of your UI, you can use it anywhere in the UI code
// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.
context.width
context.height
// Gives you the power to define half the screen, a third of it and so on.
// Useful for responsive applications.
// param dividedBy (double) optional - default: 1
// param reducedBy (double) optional - default: 0
context.heightTransformer()
context.widthTransformer()
/// Similar to MediaQuery.of(context).size
context.mediaQuerySize()
/// Similar to MediaQuery.of(context).padding
context.mediaQueryPadding()
/// Similar to MediaQuery.of(context).viewPadding
context.mediaQueryViewPadding()
/// Similar to MediaQuery.of(context).viewInsets;
context.mediaQueryViewInsets()
/// Similar to MediaQuery.of(context).orientation;
context.orientation()
/// Check if device is on landscape mode
context.isLandscape()
/// Check if device is on portrait mode
context.isPortrait()
/// Similar to MediaQuery.of(context).devicePixelRatio;
context.devicePixelRatio()
/// Similar to MediaQuery.of(context).textScaleFactor;
context.textScaleFactor()
/// Get the shortestSide from screen
context.mediaQueryShortestSide()
/// True if width be larger than 800
context.showNavbar()
/// True if the shortestSide is smaller than 600p
context.isPhone()
/// True if the shortestSide is largest than 600p
context.isSmallTablet()
/// True if the shortestSide is largest than 720p
context.isLargeTablet()
/// True if the current device is Tablet
context.isTablet()
/// Returns a value<T> according to the screen size
/// can give value for:
/// watch: if the shortestSide is smaller than 300
/// mobile: if the shortestSide is smaller than 600
/// tablet: if the shortestSide is smaller than 1200
/// desktop: if width is largest than 1200
context.responsiveValue<T>()
```
### Optional Global Settings and Manual configurations
GetMaterialApp configures everything for you, but if you want to configure Get manually.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
```
You will also be able to use your own Middleware within `GetObserver`, this will not influence anything.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // Here
],
);
```
You can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route.
Or do it directly in your `GetMaterialApp`
```dart
GetMaterialApp(
enableLog: true,
defaultTransition: Transition.fade,
opaqueRoute: Get.isOpaqueRouteDefault,
popGesture: Get.isPopGestureEnable,
transitionDuration: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino
)
```
You can optionally redirect all the logging messages from `Get`.
If you want to use your own, favourite logging package,
and want to capture the logs there:
```dart
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// pass the message to your favourite logging package here
// please note that even if enableLog: false log messages will be pushed in this callback
// you get check the flag if you want through GetConfig.isLogEnable
}
```
### Local State Widgets
These Widgets allows you to manage a single value, and keep the state ephemeral and locally.
We have flavours for Reactive and Simple.
For instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom
Expandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content
of the body in a `Scaffold`.
#### ValueBuilder
A simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value.
```dart
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )
),
// if you need to call something outside the builder method.
onUpdate: (value) => print("Value updated: $value"),
onDispose: () => print("Widget unmounted"),
),
```
#### ObxValue
Similar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and
updates automatically... isn't it awesome?
```dart
ObxValue((data) => Switch(
value: data.value,
onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,
),
false.obs,
),
```
## Useful tips
`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators.
> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!
> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code
> looks cleaner, but:
```dart
var message = 'Hello world'.obs;
print( 'Message "$message" has Type ${message.runtimeType}');
```
Even if `message` _prints_ the actual String value, the Type is **RxString**!
So, you can't do `message.substring( 0, 4 )`.
You have to access the real `value` inside the _observable_:
The most "used way" is `.value`, but, did you know that you can also use...
```dart
final name = 'GetX'.obs;
// only "updates" the stream, if the value is different from the current one.
name.value = 'Hey';
// All Rx properties are "callable" and returns the new value.
// but this approach does not accepts `null`, the UI will not rebuild.
name('Hello');
// is like a getter, prints 'Hello'.
name() ;
/// numbers:
final count = 0.obs;
// You can use all non mutable operations from num primitives!
count + 1;
// Watch out! this is only valid if `count` is not final, but var
count += 1;
// You can also compare against values:
count > 2;
/// booleans:
final flag = false.obs;
// switches the value between true/false
flag.toggle();
/// all types:
// Sets the `value` to null.
flag.nil();
// All toString(), toJson() operations are passed down to the `value`
print( count ); // calls `toString()` inside for RxInt
final abc = [0,1,2].obs;
// Converts the value to a json Array, prints RxList
// Json is supported by all Rx types!
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap, RxList and RxSet are special Rx types, that extends their native types.
// but you can work with a List as a regular list, although is reactive!
abc.add(12); // pushes 12 to the list, and UPDATES the stream.
abc[3]; // like Lists, reads the index 3.
// equality works with the Rx and the value, but hashCode is always taken from the value
final number = 12.obs;
print( number == 12 ); // prints > true
/// Custom Rx Models:
// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age years old';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
// `user` is "reactive", but the properties inside ARE NOT!
// So, if we change some variable inside of it...
user.value.name = 'Roi';
// The widget will not rebuild!,
// `Rx` don't have any clue when you change something inside user.
// So, for custom classes, we need to manually "notify" the change.
user.refresh();
// or we can use the `update()` method!
user.update((value){
value.name='Roi';
});
print( user );
```
## StateMixin
Another way to handle your `UI` state is use the `StateMixin<T>` .
To implement it, use the `with` to add the `StateMixin<T>`
to your controller which allows a T model.
```dart
class Controller extends GetController with StateMixin<User>{}
```
The `change()` method change the State whenever we want.
Just pass the data and the status in this way:
```dart
change(data, status: RxStatus.success());
```
RxStatus allow these status:
```dart
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');
```
To represent it in the UI, use:
```dart
class OtherClass extends GetView<Controller> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.obx(
(state)=>Text(state.name),
// here you can put your custom loading indicator, but
// by default would be Center(child:CircularProgressIndicator())
onLoading: CustomLoadingIndicator(),
onEmpty: Text('No data found'),
// here also you can set your own error widget, but by
// default will be an Center(child:Text(error))
onError: (error)=>Text(error),
),
);
}
```
#### GetView
I love this Widget, is so simple, yet, so useful!
Is a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all.
```dart
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
// ALWAYS remember to pass the `Type` you used to register your controller!
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // just call `controller.something`
);
}
}
```
#### GetResponsiveView
Extend this widget to build responsive view.
this widget contains the `screen` property that have all
information about the screen size and type.
##### How to use it
You have two options to build it.
- with `builder` method you return the widget to build.
- with methods `desktop`, `tablet`,`phone`, `watch`. the specific
method will be built when the screen type matches the method
when the screen is [ScreenType.Tablet] the `tablet` method
will be exuded and so on.
**Note:** If you use this method please set the property `alwaysUseBuilder` to `false`
With `settings` property you can set the width limit for the screen types.
![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
Code to this screen
[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
#### GetWidget
Most people have no idea about this Widget, or totally confuse the usage of it.
The use case is very rare, but very specific: It `caches` a Controller.
Because of the _cache_, can't be a `const Stateless`.
> So, when do you need to "cache" a Controller?
If you use, another "not so common" feature of **GetX**: `Get.create()`.
`Get.create(()=>Controller())` will generate a new `Controller` each time you call
`Get.find<Controller>()`,
That's where `GetWidget` shines... as you can use it, for example,
to keep a list of Todo items. So, if the widget gets "rebuilt", it will keep the same controller instance.
#### GetxService
This class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).
But has no "logic" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass
**can not** be removed from memory.
So is super useful to keep your "Services" always reachable and active with `Get.find()`. Like:
`ApiService`, `StorageService`, `CacheService`.
```dart
Future<void> main() async {
await initServices(); /// AWAIT SERVICES INITIALIZATION.
runApp(SomeApp());
}
/// Is a smart move to make your Services intiialize before you run the Flutter app.
/// as you can control the execution flow (maybe you need to load some Theme configuration,
/// apiKey, language defined by the User... so load SettingService before running ApiService.
/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.
void initServices() async {
print('starting services ...');
/// Here is where you put get_storage, hive, shared_pref initialization.
/// or moor connection, or whatever that's async.
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
```
The only way to actually delete a `GetxService`, is with `Get.reset()` which is like a
"Hot Reboot" of your app. So remember, if you need absolute persistence of a class instance during the
lifetime of your app, use `GetxService`.
### Tests
You can test your controllers like any other class, including their lifecycles:
```dart
class Controller extends GetxController {
@override
void onInit() {
super.onInit();
//Change value to name2
name.value = 'name2';
}
@override
void onClose() {
name.value = '';
super.onClose();
}
final name = 'name1'.obs;
void changeName() => name.value = 'name3';
}
void main() {
test('''
Test the state of the reactive variable "name" across all of its lifecycles''',
() {
/// You can test the controller without the lifecycle,
/// but it's not recommended unless you're not using
/// GetX dependency injection
final controller = Controller();
expect(controller.name.value, 'name1');
/// If you are using it, you can test everything,
/// including the state of the application after each lifecycle.
Get.put(controller); // onInit was called
expect(controller.name.value, 'name2');
/// Test your functions
controller.changeName();
expect(controller.name.value, 'name3');
/// onClose was called
Get.delete<Controller>();
expect(controller.name.value, '');
});
}
```
#### Tips
##### Mockito or mocktail
If you need to mock your GetxController/GetxService, you should extend GetxController, and mixin it with Mock, that way
```dart
class NotificationServiceMock extends GetxService with Mock implements NotificationService {}
```
##### Using Get.reset()
If you are testing widgets, or test groups, use Get.reset at the end of your test or in tearDown to reset all settings from your previous test.
##### Get.testMode
if you are using your navigation in your controllers, use `Get.testMode = true` at the beginning of your main.
# Breaking changes from 2.0
1- Rx types:
| Before | After |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RxController and GetBuilder now have merged, you no longer need to memorize which controller you want to use, just use GetxController, it will work for simple state management and for reactive as well.
2- NamedRoutes
Before:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
Now:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
```
Why this change?
Often, it may be necessary to decide which page will be displayed from a parameter, or a login token, the previous approach was inflexible, as it did not allow this.
Inserting the page into a function has significantly reduced the RAM consumption, since the routes will not be allocated in memory since the app was started, and it also allowed to do this type of approach:
```dart
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
# Why Getx?
1- Many times after a Flutter update, many of your packages will break. Sometimes compilation errors happen, errors often appear that there are still no answers about, and the developer needs to know where the error came from, track the error, only then try to open an issue in the corresponding repository, and see its problem solved. Get centralizes the main resources for development (State, dependency and route management), allowing you to add a single package to your pubspec, and start working. After a Flutter update, the only thing you need to do is update the Get dependency, and get to work. Get also resolves compatibility issues. How many times a version of a package is not compatible with the version of another, because one uses a dependency in one version, and the other in another version? This is also not a concern using Get, as everything is in the same package and is fully compatible.
2- Flutter is easy, Flutter is incredible, but Flutter still has some boilerplate that may be unwanted for most developers, such as `Navigator.of(context).push (context, builder [...]`. Get simplifies development. Instead of writing 8 lines of code to just call a route, you can just do it: `Get.to(Home())` and you're done, you'll go to the next page. Dynamic web urls are a really painful thing to do with Flutter currently, and that with GetX is stupidly simple. Managing states in Flutter, and managing dependencies is also something that generates a lot of discussion, as there are hundreds of patterns in the pub. But there is nothing as easy as adding a ".obs" at the end of your variable, and place your widget inside an Obx, and that's it, all updates to that variable will be automatically updated on the screen.
3- Ease without worrying about performance. Flutter's performance is already amazing, but imagine that you use a state manager, and a locator to distribute your blocs/stores/controllers/ etc. classes. You will have to manually call the exclusion of that dependency when you don't need it. But have you ever thought of simply using your controller, and when it was no longer being used by anyone, it would simply be deleted from memory? That's what GetX does. With SmartManagement, everything that is not being used is deleted from memory, and you shouldn't have to worry about anything but programming. You will be assured that you are consuming the minimum necessary resources, without even having created a logic for this.
4- Actual decoupling. You may have heard the concept "separate the view from the business logic". This is not a peculiarity of BLoC, MVC, MVVM, and any other standard on the market has this concept. However, this concept can often be mitigated in Flutter due to the use of context.
If you need context to find an InheritedWidget, you need it in the view, or pass the context by parameter. I particularly find this solution very ugly, and to work in teams we will always have a dependence on View's business logic. Getx is unorthodox with the standard approach, and while it does not completely ban the use of StatefulWidgets, InitState, etc., it always has a similar approach that can be cleaner. Controllers have life cycles, and when you need to make an APIREST request for example, you don't depend on anything in the view. You can use onInit to initiate the http call, and when the data arrives, the variables will be populated. As GetX is fully reactive (really, and works under streams), once the items are filled, all widgets that use that variable will be automatically updated in the view. This allows people with UI expertise to work only with widgets, and not have to send anything to business logic other than user events (like clicking a button), while people working with business logic will be free to create and test the business logic separately.
This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.
# Community
## Community channels
GetX has a highly active and helpful community. If you have questions, or would like any assistance regarding the use of this framework, please join our community channels, your question will be answered more quickly, and it will be the most suitable place. This repository is exclusive for opening issues, and requesting resources, but feel free to be part of GetX Community.
| **Slack** | **Discord** | **Telegram** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
## How to contribute
_Want to contribute to the project? We will be proud to highlight you as one of our collaborators. Here are some points where you can contribute and make Get (and Flutter) even better._
- Helping to translate the readme into other languages.
- Adding documentation to the readme (a lot of Get's functions haven't been documented yet).
- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki).
- Offering PRs for code/tests.
- Including new functions.
Any contribution is welcome!
## Articles and videos
- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).
- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.
- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.
- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.
- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.
- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.
- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman).
- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman).
- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli.
- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli.
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
</div>
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
*Idiomas: Español (este archivo), [Indonesio](README.id-ID.md), [Urdu](README.ur-PK.md), [Lengua china](README.zh-cn.md), [Inglés](README.md), [Portugués de Brasil](README.pt-br.md), [Ruso](README.ru.md), [Polaco](README.pl.md), [Coreano](README.ko-kr.md), [Francés](README-fr.md).*
*Idiomas: Español (este archivo), [Vietnamita](README-vi.md), [Indonesio](README.id-ID.md), [Urdu](README.ur-PK.md), [Lengua china](README.zh-cn.md), [Inglés](README.md), [Portugués de Brasil](README.pt-br.md), [Ruso](README.ru.md), [Polaco](README.pl.md), [Coreano](README.ko-kr.md), [Francés](README-fr.md).*
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
... ... @@ -17,11 +20,9 @@
<h3>Lamentamos la inconsistencia en la traducción. El paquete GetX se actualiza con bastante frecuencia y es posible que las traducciones a documentos no sean tan rápidas. Entonces, para que esta documentación aún tenga todo el contenido, dejaré aquí todos los textos nuevos sin traducir (considero que es mejor tener los documentos en inglés que no tenerlos), por lo que si alguien quiere traducir, sería de gran ayuda 😁</h3>
- [Communication and support channels:](#communication-and-support-channels)
- [Sobre GetX](#sobre-getx)
- [Como contribuir](#como-contribuir)
- [Installing](#installing)
- [Proyecto Counter no GetX](#proyecto-counter-no-getx)
- [Instalación](#instalación)
- [Proyecto contador con GetX](#proyecto-contador-con-getx)
- [Los tres pilares](#los-tres-pilares)
- [Gestión del Estado](#gestión-del-estado)
- [Reactivo STATE_MANAGER](#reactivo-state_manager)
... ... @@ -37,25 +38,21 @@
- [Otras API avanzadas y configuraciones manuales](#otras-api-avanzadas-y-configuraciones-manuales)
- [Configuraciones globales opcionales](#configuraciones-globales-opcionales)
- [Video explanation of Other GetX Features](#video-explanation-of-other-getx-features)
- [Rompiendo cambios desde 2.0](#rompiendo-cambios-desde-20)
- [Cambios importantes desde 2.0](#cambios-importantes-desde-20)
- [¿Por qué Getx?](#por-qué-getx)
# Communication and support channels:
[**Slack (Inglés)**](https://communityinviter.com/apps/getxworkspace/getx)
[**Discord (Ingles y Portugués)**](https://discord.com/invite/9Y3wK9)
[**Telegram (Portugués)**](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
- [Comunidad](#comunidad)
- [Canales de la comunidad](#canales-de-la-comunidad)
- [Cómo contribuir](#cómo-contribuir)
- [Artículos y vídeos](#artículos-y-vídeos-inglés)
# Sobre GetX
- GetX es una solución extra ligera y potente para Flutter. Combina gestión de estádo de alto rendimiento, inyección de dependencia inteligente y gestión de rutas, de forma rápida y práctica.
- GetX es una solución extra ligera y potente para Flutter. Combina gestión de estádo de alto rendimiento, inyección de dependencia inteligente y gestión de rutas de forma rápida y práctica.
- GetX tiene 3 principios básicos, esto significa que esta es la prioridad para todos los recursos de la biblioteca.
**PERFORMANCE:** GetX se centra en el rendimiento y el consumo mínimo de recursos. Los puntos de referencia casi siempre no son importantes en el mundo real, pero si lo desea, aquí hay un indicador de consumo.([benchmarks](https://github.com/jonataslaw/benchmarks)), donde GetX lo hace mejor que otros enfoques de gestión estatal, por ejemplo. La diferencia no es grande, pero muestra nuestra preocupación por no desperdiciar sus recursos.
**PRODUCTIVITY:** GetX utiliza una sintaxis fácil y agradable.
**ORGANIZATION:** GetX permite el desacoplamiento total de la vista de la lógica empresarial.
- **RENDIMIENTO:** GetX se centra en el rendimiento y el consumo mínimo de recursos. Los puntos de referencia casi siempre no son importantes en el mundo real, pero si lo desea, aquí hay un indicador de consumo.([benchmarks](https://github.com/jonataslaw/benchmarks)), donde GetX lo hace mejor que otros enfoques de gestión estatal, por ejemplo. La diferencia no es grande, pero muestra nuestra preocupación por no desperdiciar sus recursos.
- **PRODUCTIVIDAD:** GetX utiliza una sintaxis fácil y agradable.
- **ORGANIZACIÓN:** GetX permite el desacoplamiento total de la vista de la lógica de negocio.
* GetX ahorrará horas de desarrollo y extraerá el máximo rendimiento que su aplicación puede ofrecer, siendo fácil para los principiantes y precisa para los expertos. Navega sin contexto, abre diálogos, snackbars o bottomsheets desde cualquier lugar de tu código, gestiona estados e inyecta dependencias de forma fácil y práctica. Get es seguro, estable, actualizado y ofrece una amplia gama de API que no están presentes en el marco predeterminado.
... ... @@ -63,54 +60,38 @@
**GetX hace que su desarrollo sea productivo, pero ¿quiere hacerlo aún más productivo? [Agregue la extensión a su VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)**
# Como contribuir
_¿Quieres contribuir al proyecto? Estaremos orgullosos de destacarte como uno de nuestros colaboradores. Aquí hay algunos puntos en los que puede contribuir y hacer que GetX (y Flutter) sea aún mejor._
# Instalación
- Ayudando a traducir el archivo Léame a otros idiomas.
- Agregar documentación al archivo Léame (ni siquiera la mitad de las funciones de GetX han sido documentadas todavía).
- Escriba artículos o haga videos que enseñen cómo usar GetX (se insertarán en el archivo Léame y en el futuro en nuestro Wiki).
- Ofreciendo PRs para código/pruebas.
- Incluyendo nuevas funciones.
# Installing
Add Get to your pubspec.yaml file:
Añada la librería Get en tu archivo pubspec.yaml:
```yaml
dependencies:
get:
```
Importar archivos get que se utilizarán:
Importe Get en los archivos en los que se utilizará:
```dart
import 'package:get/get.dart';
```
# Proyecto Counter no GetX
# Proyecto Contador con GetX
Vea una explicación más detallada de la administración del estado [aquí](./documentation/es_ES/state_management.md). Allí verá más ejemplos y también la diferencia entre el Gestión del Estado simple y el Gestión del Estado reactivo
El proyecto "contador" creado por defecto en un nuevo proyecto en Flutter tiene más de 100 líneas (con comentarios). Para mostrar el poder de GetX, demostraré cómo hacer un "contador" cambiando el estado con cada clic, cambiando de página y compartiendo el estado entre pantallas, todo de manera organizada, separando la vista de la lógica de negocio, SOLO 26 LÍNEAS DE CÓDIGO INCLUIDOS COMENTARIOS.
- Paso 1:
Agregue "Get" antes de su materialApp, convirtiéndolo en GetMaterialApp
- Paso 1: Agregue "Get" antes de su materialApp, convirtiéndolo en GetMaterialApp
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
**Nota**: esto no modifica el MaterialApp del Flutter, GetMaterialApp no es una MaterialApp modificado, es solo un Widget preconfigurado, que tiene como child un MaterialApp por defecto. Puede configurar esto manualmente, pero definitivamente no es necesario. GetMaterialApp creará rutas, las inyectará, inyectará traducciones, inyectará todo lo que necesita para la navegación de rutas. Si usa Get solo para la gestión de estado o dependencias, no es necesario usar GetMaterialApp. GetMaterialApp es necesario para rutas, snackbars, internacionalización, bottomSheets, diálogos y APIs de alto nivel relacionadas con rutas y ausencia de contexto.
**Nota**: esto no modifica el MaterialApp del Flutter, GetMaterialApp no es una MaterialApp modificado, es solo un Widget preconfigurado que tiene como child un MaterialApp por defecto. Puede configurar esto manualmente, pero definitivamente no es necesario. GetMaterialApp creará rutas, las inyectará, inyectará traducciones, inyectará todo lo que necesita para la navegación de rutas. Si usa Get solo para la gestión de estado o dependencias, no es necesario usar GetMaterialApp. GetMaterialApp es necesario para rutas, snackbars, internacionalización, bottomSheets, diálogos y APIs de alto nivel relacionadas con rutas y ausencia de contexto.
**Note²:** Este paso solo es necesario si vas a usar route management (`Get.to()`, `Get.back()` y así). Si no lo va a usar, no es necesario que realice el paso 1
**Nota²:** Este paso solo es necesario si va a usar route management (`Get.to()`, `Get.back()` y así). Si no lo va a usar, no es necesario que realice el paso 1
- Paso 2:
Cree su clase con la lógica de negocio colocando todas las variables, métodos y controladores dentro de ella. Puede hacer que cualquier variable sea observable usando un simple ".obs".
- Paso 2: Cree su clase con la lógica de negocio colocando todas las variables, métodos y controladores dentro de ella. Puede hacer que cualquier variable sea observable usando un simple ".obs".
```dart
class Controller extends GetxController {
... ... @@ -119,8 +100,7 @@ class Controller extends GetxController {
}
```
- Paso 3:
Cree su vista, use StatelessWidget y ahorre algo de RAM, con GetX ya no necesitará usar StatefulWidget.
- Paso 3: Cree su vista, use StatelessWidget y ahorre algo de RAM, con GetX ya no necesitará usar StatefulWidget.
```dart
class Home extends StatelessWidget {
... ... @@ -483,21 +463,18 @@ void localLogWriter(String text, {bool isError = false}) {
Amateur Coder hizo un video asombroso sobre utilidades, almacenamiento, enlaces y otras características! Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)
# Rompiendo cambios desde 2.0
# Cambios importantes desde 2.0
1- Rx types:
Antes: StringX ahora: RxString
Antes: IntX ahora: RxInt
Antes: MapX ahora: RxMap
Antes: ListX ahora: RxList
Antes: NumX ahora: RxNum
Antes: RxDouble ahora: RxDouble
| Antes | Ahora |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RxController y GetBuilder ahora se han fusionado, ya no necesita memorizar qué controlador desea usar, solo use GetXController, funcionará para gestión de estádo simple y también para reactivo.
... ... @@ -553,3 +530,49 @@ GetMaterialApp(
Si necesita contexto para encontrar un InheritedWidget, lo necesita en la vista o pasado por parámetro. En particular, encuentro esta solución muy fea, y para trabajar en equipo siempre tendremos una dependencia de la lógica de negocios de la vista. Getx no es ortodoxo con el enfoque estándar, y aunque no prohíbe completamente el uso de StatefulWidgets, InitState, etc., siempre tiene un enfoque similar que puede ser más limpio. Los controladores tienen ciclos de vida, y cuando necesita hacer una solicitud API REST, por ejemplo, no depende de nada en la vista. Puede usar onInit para iniciar la llamada http, y cuando lleguen los datos, se rellenarán las variables. Como GetX es completamente reactivo (realmente, y funciona bajo streams), una vez que se llenan los elementos, todos los widgets que usan esa variable se actualizarán automáticamente en la vista. Esto permite que las personas con experiencia en IU trabajen solo con widgets y no tengan que enviar nada a la lógica de negocios que no sean eventos de usuario (como hacer clic en un botón), mientras que las personas que trabajan con lógica de negocios podrán crearla y probarla por separado.
Esta librería siempre se actualizará e implementará nuevas características. Siéntase libre de ofrecer PRs y contribuir a ellas.
# Comunidad
## Canales de la comunidad
GetX tiene una comunidad muy activa e implicada. Si tiene dudas, o necesita cualquier tipo de asistencia sobre el uso de este framework, no dude en unirse a nuestr, tu duda será resuelta lo antes posible. Este repositorio es de uso exclusivo para abrir issues, pero siéntase libre de unirse a la Comunidad de GetX.
| **Slack (🇬🇧)** | **Discord (🇬🇧 y 🇵🇹)** | **Telegram (🇵🇹)** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
# Cómo contribuir
_¿Quieres contribuir al proyecto? Estaremos orgullosos de destacarte como uno de nuestros colaboradores. Aquí hay algunos puntos en los que puede contribuir y hacer que GetX (y Flutter) sea aún mejor._
- Ayudando a traducir el archivo Léame a otros idiomas.
- Agregar documentación al archivo Léame (ni siquiera la mitad de las funciones de GetX han sido documentadas todavía).
- Escriba artículos o haga videos que enseñen cómo usar GetX (se insertarán en el archivo Léame y en el futuro en nuestro Wiki).
- Ofreciendo PRs para código/pruebas.
- Incluyendo nuevas funciones.
¡Cualquier contribución es bienvenida!
## Artículos y vídeos (inglés)
- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).
- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.
- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.
- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.
- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.
- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.
- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman).
- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman).
- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli.
- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli.
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**Langues: Français (Ce fichier), [Anglais](README.md), [Indonésien](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinois](README.zh-cn.md), [Portuguais du Brésil](README.pt-br.md), [Espagnol](README-es.md), [Russe](README.ru.md), [Polonais](README.pl.md), [Koréen](README.ko-kr.md).**
**Langues: Français (Ce fichier), [Anglais](README.md), [Vietnamien](README-vi.md), [Indonésien](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinois](README.zh-cn.md), [Portuguais du Brésil](README.pt-br.md), [Espagnol](README-es.md), [Russe](README.ru.md), [Polonais](README.pl.md), [Koréen](README.ko-kr.md).**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
... ... @@ -75,13 +77,13 @@
- **PRODUCTIVITÉ:** GetX utilise une syntaxe simple et agréable. Peu importe ce que vous voulez faire, il existe toujours un moyen plus simple avec GetX. Cela économisera des heures de développement et fournira les performances maximales que votre application peut offrir.
En règle générale, le développeur doit s'occuper lui-même de la suppression des contrôleurs de la mémoire. Avec GetX, cela n'est pas nécessaire car les ressources sont, par défaut, supprimées de la mémoire lorsqu'elles ne sont pas utilisées. Si vous souhaitez les conserver en mémoire, vous devez déclarer explicitement "permanent: true" comme paramètre lors de la création de la ressource. De cette façon, en plus de gagner du temps, vous risquez moins d'avoir des ressources inutiles dans la mémoire. L'initialisation des ressources est également 'lazy' par défaut (i.e. se fait seulement lorsque la ressource est nécessaire).
- **ORGANIZATION:** GetX permet le découplage total de la Vue (View), de la Logique de Présentation (Presentation Logic), de la Business Logic, de l'injection de dépendances (Dependency Injection) et de la Navigation. Vous n'avez pas besoin de contexte pour naviguer entre les routes, vous n'êtes donc pas dépendant de la hiérarchisation des widgets (visualisation) pour cela. Vous n'avez pas besoin de 'context' pour accéder à vos contrôleurs/blocs via un inheritedWidget, vous dissociez donc complètement votre logique de présentation (Vue) et votre Business logic de votre couche de visualisation. Vous n'avez pas besoin d'injecter vos classes Controlleûrs / Modèles / Blocs le long de la hiérarchie de Widgets via `MultiProvider`. Pour cela, GetX utilise sa propre fonction d'injection de dépendances (DI), découplant complètement la DI de sa Vue.
Avec GetX, vous savez où trouver chaque module de votre application, avec un code propre par défaut. En plus de rendre la maintenance facile, cela rend le partage de modules quelque chose qui jusque-là dans Flutter était impensable, quelque chose de totalement possible.
BLoC était un point de départ pour organiser le code dans Flutter, il sépare la Business logic de la visualisation. GetX en est une évolution naturelle, séparant non seulement la Business logic mais aussi la logique de présentation. L'injection de dépendances et les routes sont également découplées, et la couche de données est séparée du tout. Vous savez où tout se trouve, et tout cela d'une manière plus facile que de construire un 'Hello World''.
GetX est le moyen le plus simple, pratique et évolutif de créer des applications hautes performances avec le SDK Flutter. Il possède un vaste écosystème qui fonctionne parfaitement, c'est facile pour les débutants et précis pour les experts. Il est sécurisé, stable, à jour et offre une vaste gamme d'API intégrées qui ne sont pas présentes dans le SDK Flutter par défaut.
- GetX possède une multitude de fonctionnalités qui vous permettent de démarrer la programmation sans vous soucier de quoi que ce soit, mais chacune de ces fonctionnalités se trouve dans des conteneurs séparés et ne démarre qu'après utilisation. Si vous n'utilisez que la gestion des états (State Management), seule la gestion des états sera compilée. Si vous n'utilisez que des routes, rien de la gestion d'état ne sera compilé.
- GetX a un énorme écosystème, une grande communauté, un grand nombre de collaborateurs, et sera maintenu tant que Flutter existera. GetX est également capable de fonctionner avec le même code sur Android, iOS, Web, Mac, Linux, Windows et sur votre serveur. Il est possible de réutiliser entièrement votre code créé sur le frontend et le backend avec Get Server.
... ... @@ -109,6 +111,7 @@ import 'package:get/get.dart';
# Application Counter avec Getx
Le projet "Counter" créé par défaut sur chaque nouveau projet Flutter comporte plus de 100 lignes (avec commentaires). Pour montrer la puissance de Get, je vais vous montrer comment faire un "compteur" changeant d'état à chaque clic, naviguer entre les pages et partager l'état entre les écrans, le tout de manière organisée, en séparant la Business logic de la Vue, en SEULEMENT 26 LIGNES DE CODE INCLUANT LES COMMENTAIRES.
- Step 1:
Ajoutez "Get" avant MaterialApp, pour le transformer en GetMaterialApp
... ... @@ -122,7 +125,7 @@ void main() => runApp(GetMaterialApp(home: Home()));
- Step 2:
Créez votre classe de Business logic et placez-y toutes les variables, méthodes et contrôleurs.
Vous pouvez rendre toute variable observable en utilisant un simple ".obs".
Vous pouvez rendre toute variable observable en utilisant un simple ".obs".
```dart
class Controller extends GetxController{
... ... @@ -217,7 +220,7 @@ Obx(() => Text("${controller.name}"));
C'est _tout_. Si simple que ca.
### Plus de details sur la gestion d Etat
### Plus de details sur la gestion d Etat
**Lire une explication plus approfondie de la gestion d'état [ici](./documentation/fr_FR/state_management.md). Là-bas, vous verrez plus d'exemples surtout pour la différence entre le gestionnaire d'état simple et le gestionnaire d'état réactif.**
... ... @@ -293,6 +296,7 @@ controller.fetchApi();
```
Imaginez que vous ayez parcouru de nombreuses routes et que vous ayez besoin de données qui ont été laissées dans votre contrôleur, vous auriez besoin d'un gestionnaire d'état combiné avec le 'Provider' ou 'Get_it', n'est-ce pas? Pas avec Get. Il vous suffit de demander à Get de "trouver" votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires:
```dart
Controller controller = Get.find();
//Oui, cela ressemble à de la magie. Get trouvera votre contrôleur et vous le livrera. Vous pouvez avoir 1 million de contrôleurs instanciés, Get vous retournera toujours le bon contrôleur.
... ... @@ -372,7 +376,7 @@ Text('logged_in'.trParams({
### Locales
'Locales' signifie lieux.
Pour definir les traductions, passer les paramètres 'locale' et 'translations' à GetMaterialApp.
Pour definir les traductions, passer les paramètres 'locale' et 'translations' à GetMaterialApp.
```dart
return GetMaterialApp(
... ... @@ -453,7 +457,6 @@ class UserProvider extends GetConnect {
### Configuration personnalisee
GetConnect est hautement personnalisable. Vous pouvez définir l'URL de base, comme modificateurs de réponse, comme modificateurs de requêtes, définir un authentificateur, et même le nombre de tentatives oú il tentera de s'authentifier, en plus de donner la possibilité de définir un décodeur standard qui transformera toutes vos Requêtes dans vos Modèles sans aucune configuration supplémentaire.
```dart
... ... @@ -463,7 +466,7 @@ class HomeProvider extends GetConnect {
// Toute 'Request' passera à jsonEncode donc CasesModel.fromJson()
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.baseUrl = 'https://api.covid19api.com';
// baseUrl = 'https://api.covid19api.com';
// baseUrl = 'https://api.covid19api.com';
// Il définit baseUrl pour Http et websockets si utilisé sans instance [httpClient]
// Cela attachera la propriété 'apikey' sur l'en-tête ('header') de toutes les 'request's
... ... @@ -493,7 +496,7 @@ class HomeProvider extends GetConnect {
// L'Autenticator sera appelé 3 fois si HttpStatus est HttpStatus.unauthorized
httpClient.maxAuthRetries = 3;
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
... ... @@ -522,11 +525,11 @@ final middlewares = [
ces middlewares seront exécutés dans cet ordre **-8 => 2 => 4 => 5**
### Redirect
Cette fonction sera appelée lors de la recherche de la page de l'itinéraire appelé. Elle reçoit RouteSettings comme résultat vers oú rediriger. Sinon donnez-lui la valeur null et il n'y aura pas de redirection.
```dart
GetPage redirect( ) {
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login');
}
... ... @@ -572,6 +575,7 @@ GetPageBuilder onPageBuildStart(GetPageBuilder page) {
```
### OnPageBuilt
Cette fonction sera appelée juste après l'appel de la fonction GetPage.page et vous donnera le résultat de la fonction et prendra le widget qui sera affiché.
### OnPageDispose
... ... @@ -798,7 +802,7 @@ ValueBuilder<bool>(
#### ObxValue
Similaire à [`ValueBuilder`](#valuebuilder), mais c'est la version Reactive, vous passez une instance Rx (rappelez-vous les .obs magiques?) et il
se met à jour automatiquement ... n'est-ce pas génial?
se met à jour automatiquement ... n'est-ce pas génial?
```dart
ObxValue((data) => Switch(
... ... @@ -977,7 +981,7 @@ pour conserver une liste de <Todo>s. Donc, si le widget est "reconstruit", il co
#### GetxService
Cette classe est comme un `GetxController`, elle partage le même cycle de vie ( `onInit()`, `onReady()`, `onClose()`), mais n'a pas de "logique" en elle.
Cette classe est comme un `GetxController`, elle partage le même cycle de vie ( `onInit()`, `onReady()`, `onClose()`), mais n'a pas de "logique" en elle.
Il notifie simplement le **GetX** Dependency Injection system, que cette sous-classe
**ne peut pas** être supprimé de la mémoire.
... ... @@ -1022,7 +1026,7 @@ class SettingsService extends GetxService {
```
La seule façon de supprimer réellement un `GetxService`, est d'utiliser` Get.reset () `qui est comme un
La seule façon de supprimer réellement un `GetxService`, est d'utiliser`Get.reset ()`qui est comme un
"Hot Reboot" de votre application. N'oubliez donc pas que si vous avez besoin d'une persistance absolue d'une instance de classe
durée de vie de votre application, utilisez `GetxService`.
... ... @@ -1041,7 +1045,6 @@ durée de vie de votre application, utilisez `GetxService`.
RxController et GetBuilder ont maintenant fusionné, vous n'avez plus besoin de mémoriser le contrôleur que vous souhaitez utiliser, utilisez simplement GetxController, cela fonctionnera pour une gestion simple de l'état et également pour la réactivité.
2- NamedRoutes
Avant:
... ... @@ -1067,6 +1070,7 @@ GetMaterialApp(
Pourquoi ce changement?
Souvent, il peut être nécessaire de décider quelle page sera affichée à partir d'un paramètre, ou d'un 'login token', l'approche précédente était inflexible, car elle ne le permettait pas.
L'insertion de la page dans une fonction a considérablement réduit la consommation de RAM, puisque les routes ne seront pas allouées en mémoire depuis le démarrage de l'application, et cela a également permis de faire ce type d'approche:
```dart
GetStorage box = GetStorage();
... ... @@ -1089,16 +1093,15 @@ GetMaterialApp(
3- Facilité sans vous soucier des performances. Les performances de Flutter sont déjà étonnantes, mais imaginez que vous utilisez un gestionnaire d'état et un localisateur pour distribuer vos classes blocs / stores / contrôleurs / etc. Vous devrez appeler manuellement l'exclusion de cette dépendance lorsque vous n'en avez pas besoin. Mais avez-vous déjà pensé à simplement utiliser votre «contrôleur`, et quand il n'était plus utilisé par personne, il serait simplement supprimé de la mémoire? C'est ce que fait GetX. Avec SmartManagement, tout ce qui n'est pas utilisé est supprimé de la mémoire et vous ne devriez pas avoir à vous soucier d'autre chose que de la programmation. Vous serez assuré de consommer le minimum de ressources nécessaires, sans même avoir créé de logique pour cela.
4- Découplage réel. Vous avez peut-être entendu le concept "séparer la vue de la business logic". Ce n'est pas une particularité de BLoC, MVC, MVVM, et tout autre standard sur le marché a ce concept. Cependant, ce concept peut souvent être atténué dans Flutter en raison de l'utilisation de `context`.
Si vous avez besoin de contexte pour trouver un InheritedWidget, vous en avez besoin dans la vue, ou passez le `context` par paramètre. Je trouve particulièrement cette solution très moche, et pour travailler en équipe, nous serons toujours dépendants de la 'business logic' de View. Getx n'est pas orthodoxe avec l'approche standard, et même s'il n'interdit pas complètement l'utilisation de StatefulWidgets, InitState, etc., il a toujours une approche similaire qui peut être plus propre. Les contrôleurs ont des cycles de vie, et lorsque vous devez faire une requête APIREST par exemple, vous ne dépendez de rien de la vue. Vous pouvez utiliser onInit pour lancer l'appel http et lorsque les données arrivent, les variables sont remplies. Comme GetX est totalement réactif (vraiment, et fonctionne sous streams), une fois les éléments remplis, tous les widgets qui utilisent cette variable seront automatiquement mis à jour dans la vue.
Cela permet aux personnes ayant une expertise de l'interface utilisateur de travailler uniquement avec des widgets et de ne pas avoir à envoyer quoi que ce soit à la business logic autre que des événements utilisateur (comme cliquer sur un bouton), tandis que les personnes travaillant avec la business logic seront libres de créer et de tester la Business logic séparément.
Si vous avez besoin de contexte pour trouver un InheritedWidget, vous en avez besoin dans la vue, ou passez le `context` par paramètre. Je trouve particulièrement cette solution très moche, et pour travailler en équipe, nous serons toujours dépendants de la 'business logic' de View. Getx n'est pas orthodoxe avec l'approche standard, et même s'il n'interdit pas complètement l'utilisation de StatefulWidgets, InitState, etc., il a toujours une approche similaire qui peut être plus propre. Les contrôleurs ont des cycles de vie, et lorsque vous devez faire une requête APIREST par exemple, vous ne dépendez de rien de la vue. Vous pouvez utiliser onInit pour lancer l'appel http et lorsque les données arrivent, les variables sont remplies. Comme GetX est totalement réactif (vraiment, et fonctionne sous streams), une fois les éléments remplis, tous les widgets qui utilisent cette variable seront automatiquement mis à jour dans la vue.
Cela permet aux personnes ayant une expertise de l'interface utilisateur de travailler uniquement avec des widgets et de ne pas avoir à envoyer quoi que ce soit à la business logic autre que des événements utilisateur (comme cliquer sur un bouton), tandis que les personnes travaillant avec la business logic seront libres de créer et de tester la Business logic séparément.
# Communite
## Chaines communautaires
GetX a une communauté très active et utile. Si vous avez des questions, ou souhaitez obtenir de l'aide concernant l'utilisation de ce framework, veuillez rejoindre nos canaux communautaires, votre question sera répondue plus rapidement, et ce sera l'endroit le plus approprié. Ce référentiel est exclusif pour l'ouverture des issues Github et la demande de ressources, mais n'hésitez pas à faire partie de la communauté GetX.
| **Slack** | **Discord** | **Telegram** |
| **Slack** | **Discord** | **Telegram** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get sur Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)
[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
<a href="https://github.com/Solido/awesome-flutter">
<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" />
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
<div align="center">
**Languages:**
[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)
[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)
[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)
[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)
[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)
[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)
[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)
[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)
[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)
[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)
[![Turkish](https://img.shields.io/badge/Language-Turkish-blueviolet?style=for-the-badge)](README.tr-TR.md)
[![Hindi](https://img.shields.io/badge/Language-Hindi-blueviolet?style=for-the-badge)](README-hi.md)
</div>
- [Get के बारे में](#about-get)
- [इंस्टॉलिंग](#installing)
- [Get के साथ काउंटर ऐप](#counter-app-with-getx)
- [तीन सिद्धांत](#the-three-pillars)
- [स्टेट मैनेजमेंट](#state-management)
- [रिएक्टिव स्टेट मैनेजर ](#reactive-state-manager)
- [स्टेट मैनेजमेंट के बारे में और जाने](#more-details-about-state-management)
- [रूट मैनेजमेंट ](#route-management)
- [रूट मैनेजमेंट के बारे में और जाने](#more-details-about-route-management)
- [डिपेंडेंसी मैनेजमेंट](#dependency-management)
- [डिपेंडेंसी मैनेजमेंट के बारे में और जाने](#more-details-about-dependency-management)
- [मदद करने वाले फीचर्स](#utils)
- [इंटरनॅशनलिनाइज़ेशन](#internationalization)
- [अनुवाद](#translations)
- [अनुवादों का उपयोग करना](#using-translations)
- [क्षेत्र के अनुसार पसंद](#locales)
- [लोकेल बदलें](#change-locale)
- [सिस्टम लोकेलस ](#system-locale)
- [थीम बदलें](#change-theme)
- [GetConnect](#getconnect)
- [डिफ़ॉल्ट कॉन्फ़िगरेशन ](#default-configuration)
- [कस्टम कॉन्फ़िगरेशन](#custom-configuration)
- [GetPage Middleware](#getpage-middleware)
- [वरीयता](#priority)
- [रीडायरेक्ट](#redirect)
- [पेज कॉल होने पर](#onpagecalled)
- [बाइंडिंग शुरू होने पर](#onbindingsstart)
- [पेज बिल्ड स्टार्ट पर](#onpagebuildstart)
- [पेज पूरा बन ने पर](#onpagebuilt)
- [पेज डिस्पोसे होने पर](#onpagedispose)
- [अन्य उन्नत एपीआई](#other-advanced-apis)
- [वैकल्पिक वैश्विक सेटिंग्स और मैन्युअल कॉन्फ़िगरेशन](#optional-global-settings-and-manual-configurations)
- [लोकल स्टेट विद्गेट्स ](#local-state-widgets)
- [वैल्यू बिल्डर](#valuebuilder)
- [ObxValue](#obxvalue)
- [उपयोगी सलाह](#useful-tips)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [इसका उपयोग कैसे करना है](#how-to-use-it)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [2.0 से बड़े बदलाव](#breaking-changes-from-20)
- [क्यों GetX?](#why-getx)
- [समुदाय](#community)
- [सामुदायिक चैनल](#community-channels)
- [कैसे योगदान करें](#how-to-contribute)
- [लेख और वीडियो](#articles-and-videos)
# Get के बारे में
- GetX, Flutter के लिए एक अतिरिक्त हल्का और शक्तिशाली समाधान है। यह स्टेट मैनेजमेंट, डिपेंडेंसी इंजेक्शन और नेविगेशन को जल्दी और व्यावहारिक रूप से जोड़ता है।
- GetX के 3 बुनियादी सिद्धांत हैं। इसका मतलब है कि पुस्तकालय में सभी संसाधनों के लिए ये प्राथमिकताएं हैं: **उत्पादकता, प्रदर्शन और संगठन।**
- **प्रदर्शन**: GetX प्रदर्शन और संसाधनों की न्यूनतम खपत पर केंद्रित है। GetX स्ट्रीम या चेंज नोटिफ़ायर का उपयोग नहीं करता है।
- **उत्पादकता**: GetX एक आसान और सुखद सिंटैक्स का उपयोग करता है। कोई फर्क नहीं पड़ता कि आप क्या करना चाहते हैं, GetX के साथ हमेशा एक आसान तरीका होता है। यह विकास के घंटों को बचाएगा और अधिकतम प्रदर्शन प्रदान करेगा जो आपका एप्लिकेशन प्रदान कर सकता है।
आम तौर पर, डेवलपर को स्मृति से नियंत्रकों को हटाने के बारे में चिंतित होना चाहिए। GetX के साथ यह आवश्यक नहीं है क्योंकि संसाधनों को स्मृति से हटा दिया जाता है जब वे डिफ़ॉल्ट रूप से उपयोग नहीं किए जाते हैं। यदि आप इसे स्मृति में रखना चाहते हैं, तो आपको अपनी निर्भरता में स्पष्ट रूप से **"permanent: true"** घोषित करना होगा। इस तरह, समय बचाने के अलावा, आपको स्मृति पर अनावश्यक निर्भरता होने का जोखिम कम होता है। डिपेंडेंसी लोडिंग भी डिफ़ॉल्ट रूप से आलसी है।
- **संगठन**: गेटएक्स व्यू, प्रेजेंटेशन लॉजिक, बिजनेस लॉजिक, डिपेंडेंसी इंजेक्शन और नेविगेशन को पूरी तरह से अलग करने की अनुमति देता है। आपको मार्गों के बीच नेविगेट करने के लिए संदर्भ की आवश्यकता नहीं है, इसलिए आप इसके लिए विजेट ट्री (विज़ुअलाइज़ेशन) पर निर्भर नहीं हैं। आपको विरासत में मिले विजेट के माध्यम से अपने नियंत्रकों/ब्लॉकों तक पहुँचने के लिए संदर्भ की आवश्यकता नहीं है, इसलिए आप अपने प्रस्तुति तर्क और व्यावसायिक तर्क को अपनी विज़ुअलाइज़ेशन परत से पूरी तरह से अलग कर सकते हैं। आपको मल्टीप्रोवाइडर्स के माध्यम से अपने विजेट ट्री में अपने कंट्रोलर/मॉडल/ब्लॉक क्लास को इंजेक्ट करने की आवश्यकता नहीं है। इसके लिए, GetX अपने स्वयं के निर्भरता इंजेक्शन सुविधा का उपयोग करता है, DI को अपने दृष्टिकोण से पूरी तरह से अलग करता है।
**GetX** के साथ आप जानते हैं कि डिफ़ॉल्ट रूप से क्लीन कोड वाले अपने एप्लिकेशन की प्रत्येक सुविधा को कहां खोजना है। रखरखाव को आसान बनाने के अलावा, यह मॉड्यूल के साझाकरण को कुछ ऐसा बनाता है जो तब तक फ़्लटर में अकल्पनीय था, कुछ पूरी तरह से संभव था।
**BLoC** फ़्लटर में कोड व्यवस्थित करने के लिए एक प्रारंभिक बिंदु था, यह व्यावसायिक तर्क को विज़ुअलाइज़ेशन से अलग करता है। GetX इसका एक स्वाभाविक विकास है, न केवल व्यावसायिक तर्क बल्कि प्रस्तुति तर्क को अलग करना। निर्भरता और मार्गों के बोनस इंजेक्शन को भी अलग कर दिया गया है, और डेटा स्तर इससे बाहर है। आप जानते हैं कि सब कुछ कहाँ है, और यह सब एक हैलो वर्ल्ड बनाने की तुलना में आसान तरीके से है।
Flutter SDK के साथ उच्च-प्रदर्शन अनुप्रयोगों के निर्माण के लिए गेटएक्स सबसे आसान, व्यावहारिक और स्केलेबल तरीका है। इसके चारों ओर एक बड़ा पारिस्थितिकी तंत्र है जो पूरी तरह से एक साथ काम करता है, यह शुरुआती लोगों के लिए आसान है, और यह विशेषज्ञों के लिए सटीक है। यह सुरक्षित, स्थिर, अप-टू-डेट है, और अंतर्निहित एपीआई की एक विशाल श्रृंखला प्रदान करता है जो डिफ़ॉल्ट फ़्लटर एसडीके में मौजूद नहीं हैं।
- **GetX** फूला हुआ नहीं है। इसमें कई विशेषताएं हैं जो आपको बिना किसी चिंता के प्रोग्रामिंग शुरू करने की अनुमति देती हैं, लेकिन इनमें से प्रत्येक सुविधा अलग-अलग कंटेनरों में होती है और केवल उपयोग के बाद ही शुरू होती है। यदि आप केवल राज्य प्रबंधन का उपयोग करते हैं, तो केवल राज्य प्रबंधन संकलित किया जाएगा। यदि आप केवल मार्गों का उपयोग करते हैं, तो राज्य प्रबंधन से कुछ भी संकलित नहीं किया जाएगा।
- GetX में एक विशाल पारिस्थितिकी तंत्र, एक बड़ा समुदाय, बड़ी संख्या में सहयोगी हैं, और जब तक फ़्लटर मौजूद है, तब तक इसे बनाए रखा जाएगा। GetX भी **Android, iOS, Web, Mac, Linux, Windows** और आपके Server पर समान Code के साथ चलने में सक्षम है।
**आपके Backend पर Frontend पर बने आपके कोड का पूरी तरह से पुन: उपयोग करना संभव है [Get Server](https://github.com/jonataslaw/get_server)**.
**इसके अलावा, संपूर्ण विकास प्रक्रिया पूरी तरह से स्वचालित हो सकती है, दोनों सर्वर पर और फ्रंट एंड पर [Get CLI](https://github.com/jonataslaw/get_cli)**.
**इसके अलावा, आपकी उत्पादकता को और बढ़ाने के लिए, हमारे पास है
**[VSCODE के लिए एक्सटेंशन](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) and the [Android Studio और Intellij के लिए एक्सटेंशन](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**
# इंस्टॉलिंग
अपनी ```pubspec.yaml``` फ़ाइल में Get को ऐड करे
```yaml
dependencies:
...
get:
```
Get को अन फाइल्स में Import करे जहां आप Get को इस्तेमाल करेंगे:
```dart
import 'package:get/get.dart';
```
# GetX के साथ काउंटर ऐप
Flutter पर नए Project पर Default रूप से बनाए गए "काउंटर" प्रोजेक्ट में 100 से अधिक लाइनें (टिप्पणियों के साथ) हैं। Get की शक्ति दिखाने के लिए, मैं प्रदर्शित करूंगा कि प्रत्येक क्लिक के साथ राज्य को बदलने वाला "काउंटर" कैसे बनाया जाए, Navigation किया जाए और State Management किया जाए, सभी एक संगठित तरीके से, व्यावसायिक तर्क को दृश्य से अलग करते हुए, केवल में टिप्पणियों सहित 26 लाइन कोड।
- चरण 1:
अपने **MaterialApp()** से पहले “Get” जोड़ें, इसे **GetMaterialApp()** में बदल दें
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
- **सूचना**: यह Flutter के MaterialApp को संशोधित नहीं करता है, GetMaterialApp एक संशोधित MaterialApp नहीं है, यह सिर्फ एक पूर्व-कॉन्फ़िगर विजेट है, जिसमें एक बच्चे के रूप में डिफ़ॉल्ट MaterialApp है। आप इसे मैन्युअल रूप से कॉन्फ़िगर कर सकते हैं, लेकिन यह निश्चित रूप से आवश्यक नहीं है। GetMaterialApp मार्ग बनाएगा, उन्हें इंजेक्ट करेगा, अनुवाद इंजेक्ट करेगा, मार्ग नेविगेशन के लिए आपको जो कुछ भी चाहिए उसे इंजेक्ट करेगा। यदि आप केवल राज्य प्रबंधन या निर्भरता प्रबंधन के लिए गेट का उपयोग करते हैं, तो GetMaterialApp का उपयोग करना आवश्यक नहीं है। GetMaterialApp मार्गों, स्नैकबार, अंतर्राष्ट्रीयकरण, बॉटमशीट, संवाद, और मार्गों से संबंधित उच्च-स्तरीय एपिस और संदर्भ की अनुपस्थिति के लिए आवश्यक है।
- **सूचना²**: यह चरण केवल तभी आवश्यक है जब आप Navigation (`Get.to()`, `Get.back()` इत्यादि) का उपयोग करने वाले हों। यदि आप इसका उपयोग नहीं करने जा रहे हैं तो चरण 1 करने की आवश्यकता नहीं है।
- चरण 2:
अपना व्यावसायिक तर्क वर्ग बनाएं और उसके अंदर सभी चर, विधियों और नियंत्रकों को रखें।
आप किसी भी Variable Ko ".obs" का प्रयोग करके Observable बना सकते है
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
- चरण 3:
अपना दृश्य बनाएं, StatelessWidget का उपयोग करें और कुछ RAM सहेजें, Get के साथ आपको StatefulWidget का उपयोग करने की आवश्यकता नहीं है।
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Get.put() का उपयोग करके अपनी Class के सभी Children के लिए उपलब्ध कराने के लिए तत्काल करें।
final Controller c = Get.put(Controller());
return Scaffold(
// जब भी गिनती बदली जाए तो Text() को अपडेट करने के लिए Obx(()=> का उपयोग करें।
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// 8 लाइन Navigator.push() को एक साधारण Get.to() से बदलें । आपको "context" की आवश्यकता नहीं है ।
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// आप किसी अन्य Page द्वारा उपयोग किए जा रहे Controller को खोजने के लिए Get से पूछ सकते हैं और आपको उस पर Redirect कर सकते हैं।
final Controller c = Get.find();
@override
Widget build(context){
// बदले हुए count Variable को Access करें
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
**परिणाम**:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
यह एक सरल Project है लेकिन यह पहले ही स्पष्ट कर देती है कि Get कितना शक्तिशाली है। जैसे-जैसे आपकी परियोजना बढ़ती है, यह अंतर और अधिक महत्वपूर्ण होता जाएगा।
Get को टीमों के साथ काम करने के लिए डिज़ाइन किया गया था, लेकिन यह व्यक्तिगत डेवलपर के काम को आसान बनाता है।
अपनी समय सीमा में सुधार करें, Performance को खोए बिना समय पर सब कुछ वितरित करें। Get हर किसी के लिए नहीं है, लेकिन अगर आपने उस वाक्यांश के साथ पहचान की है, तो Get आपके लिए है!
# तीन सिद्धांत
## State management
Get के दो अलग-अलग State Manager हैं: Simple State Builder (हम इसे GetBuilder कहते हैं) और Reactive State Manager (GetX/Obx)
### Reactive State Manager
Reactive Programming कई लोगों को अलग-थलग कर सकती है क्योंकि इसे जटिल कहा जाता है। GetX Reactive Programming को काफी सरल बना देता है:
- आपको StreamControllers बनाने की आवश्यकता नहीं होगी।
- आपको प्रत्येक Variable के लिए StreamBuilder बनाने की आवश्यकता नहीं होगी
- आपको प्रत्येक Class के लिए एक State बनाने की आवश्यकता नहीं होगी।
- आपको Initial Value के लिए एक Get बनाने की आवश्यकता नहीं होगी।
- आपको Code Generators का उपयोग करने की आवश्यकता नहीं होगी
**Get** के साथ **Reactive Programming**, **"setState()"** का उपयोग करने जितना आसान है।
आइए कल्पना करें कि आपके पास एक name Variable है और चाहते हैं कि हर बार जब आप इसे बदलते हैं, तो इसका उपयोग करने वाले सभी Widgets बदल जाएँ ।
यह आपका count Variable है
```dart
var name = 'Adison Masih';
```
इसे Observable बनाने के लिए, आपको बस इसके अंत में ".obs" जोड़ना होगा:
```dart
var name = 'Adison Masih'.obs;
```
अगर आप आप उस Value को दिखाना चाहते हैं और जब भी Value बदलती हैं तो स्क्रीन को करना चाहते हैं, तो यह करें:
```dart
Obx(() => Text("${controller.name}"));
```
बस इतना ही। यह _इत्ना_ आसान है।
### State Management के बारे में अधिक जानकारी
राज्य प्रबंधन की अधिक गहन व्याख्या [यहां](./documentation/en_US/state_management.md) देखें । वहां आपको अधिक उदाहरण और **Simple State Manager** और **Reactive State Manager** के बीच का अंतर दिखाई देगा
आपको GetX की शक्ति का अच्छा अंदाजा हो जाएगा।
## Route प्रबंधन
यदि आप बिना **context** के **Routes/Snackbars/Dialogs/Bottomsheets** का उपयोग करने जा रहे हैं, तो GetX आपके लिए भी उत्कृष्ट है, बस इसे देखें:
अपने **"MaterialApp()"** से पहले **“Get”** जोड़ें, इसे **"GetMaterialApp()"** में बदल दें
```dart
GetMaterialApp( // यह पहले MaterialApp था
home: MyHome(),
)
```
एक नई स्क्रीन पर Navigate करें:
```dart
Get.to(NextScreen());
```
नाम के साथ नई स्क्रीन पर Navigate करें। **Named Routes** पर अधिक विवरण [यहां](./documentation/en_US/route_management.md#navigation-with-named-routes) देखें।
```dart
Get.toNamed('/details');
```
Snackbar, Dialog तथा Bottomsheets या ऐसी किसी भी चीज़ को बंद करने के लिए आप आम तौर पर ```Navigator.pop(context);``` के साथ बंद करते हैं;
```dart
Get.back();
```
अगली Screen पर जाने के लिए और पिछली Screen पर वापस जाने का कोई विकल्प नहीं है (SplashScreens, Login Screens आदि में उपयोग के लिए)
```dart
Get.off(NextScreen());
```
अगली Screen पर जाने और पिछले सभी Routes को रद्द करने के लिए (Shopping Carts, Polls और Tests में उपयोगी)
```dart
Get.offAll(NextScreen());
```
ध्यान दिया कि आपको इनमें से कोई भी काम करने के लिए **"context"** का उपयोग करने की आवश्यकता नहीं है? **"Get Route Management"** का उपयोग करने का यह सबसे बड़ा लाभ है। इसके साथ, आप इन सभी **"Methods"** को अपने **"Controller Class"** से बिना किसी चिंता के Execute कर सकते हैं।
### Route Management के बारे में अधिक जानकारी
**"Named Routes"** के साथ काम करें और अपने Routes पर **"Lower-Level Control"** भी प्राप्त करें! [यहां](./documentation/en_US/route_management.md) गहन दस्तावेज है
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**Ngôn ngữ: Tiếng Việt (file này), [English](README.md), [Indonesian](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinese](README.zh-cn.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), [Russian](README.ru.md), [Polish](README.pl.md), [Korean](README.ko-kr.md), [French](README-fr.md).**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)
[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
<a href="https://github.com/Solido/awesome-flutter">
<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" />
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
- [Về GetX](#về-getx)
- [Cài Đặt](#cài-đặt)
- [Counter App với GetX](#counter-app-với-getx)
- [Tam Trụ](#tam-trụ)
- [Quản lý State](#quản-lý-state)
- [Quản lý Reactive State](#quản-lý-reactive-state)
- [Thêm thông tin về quản lý state](#thêm-thông-tin-về-quản-lý-state)
- [Quản lý route](#quản-lý-route)
- [Thêm thông tin về quản lý route](#thêm-thông-tin-về-quản-lý-route)
- [Quản lý dependency](#quản-lý-dependency)
- [Thêm thông tin về quản lý dependency](#thêm-thông-tin-về-quản-lý-dependency)
- [Utils](#utils)
- [Internationalization](#internationalization)
- [Dịch thuật](#dịch-thuật)
- [Sử dụng bản dịch thuật](#sử-dụng-bản-dịch-thuật)
- [Locales](#locales)
- [Đổi locale](#đổi-locale)
- [System locale](#system-locale)
- [Đổi Theme](#đổi-theme)
- [GetConnect](#getconnect)
- [Cấu hình mặc định](#cấu-hình-mặc-định)
- [Cấu hình tùy chỉnh](#cấu-hình-tùy-chỉnh)
- [GetPage Middleware](#getpage-middleware)
- [Ưu tiên](#ưu-tiên)
- [Chuyển hướng](#chuyển-hướng)
- [onPageCalled](#onpagecalled)
- [OnBindingsStart](#onbindingsstart)
- [OnPageBuildStart](#onpagebuildstart)
- [OnPageBuilt](#onpagebuilt)
- [OnPageDispose](#onpagedispose)
- [APIs nâng cao khác](#apis-nâng-cao-khác)
- [Cấu hình thủ công và cài đặt chung tuỳ chọn](#cấu-hình-thủ-công-và-cài-đặt-chung-tuỳ-chọn)
- [Local State Widgets](#local-state-widgets)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [Mẹo hữu ích](#mẹo-hữu-ích)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [Hướng dẫn sử dụng trước khi dùng](#hướng-dẫn-sử-dụng-trước-khi-dùng)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [Thay đổi đột phá 2.0](#thay-đổi-đột-phá-2.0)
- [Tại sao lại dùng GetX](#tại-sao-lại-dùng-getx)
- [Cộng đồng](#cộng-đồng)
- [Kênh Cộng đồng](#kênh-cộng-đồng)
- [Cách cống hiến](#cách-cống-hiến)
- [Các bài báo và video](#các-bài-báo-và-video)
# Về GetX
- GetX hướng tới sự nhỏ gọn và giải pháp tối ưu cho Flutter với tốc độ ưu việt trong quản lý state, nạp dependency thông minh, và quản lý route nhanh chóng và thực tế.
- GetX hướng tới 3 tham vọng chính, nghĩa là tất cả các tài nguyên của thư viện sẽ dành cho những điểm ưu tiên sau: **NĂNG SUẤT, HIỆU SUẤT VÀ TỔ CHỨC.**
- **HIỆU SUẤT:** GetX tập trung vào hiệu suất và mức tiêu thụ tài nguyên tối thiểu, do đó nó không sử dụng Streams hoặc ChangeNotifier.
- **NĂNG SUẤT:** GetX sử dụng một cú pháp dễ dàng và dễ thở. Bất kể bạn muốn làm gì, luôn có một cách dễ dàng hơn với GetX. Nó sẽ tiết kiệm hàng giờ phát triển và sẽ cung cấp hiệu suất tối đa mà ứng dụng của bạn có thể mang lại.
Nói chung, nhà phát triển nên quan tâm đến việc xóa những controller ra khỏi bộ nhớ. Với GetX, mặc định các tài nguyên sẽ
TỰ ĐỘNG xóa khỏi bộ nhớ khi không dùng nữa. Nếu bạn muốn giữ nó trong bộ nhớ, bạn phải khai báo rõ ràng "permanent: true" trong phần dependency của mình. Từ đó, bạn sẽ tiết kiệm thời gian và giảm rủi ro khi phụ thuộc vào bộ nhớ. Theo mặc định, tính năng tải dependency cũng lười biếng.
- **TỔ CHỨC:**
GetX cho phép tách toàn bộ View, presentation logic, business logic, nạp dependencies và điều hướng. Bạn không cần "context" để điều hướng giữa các route, vì vậy bạn sẽ độc lập trong sơ đồ widget (trực quan hóa). Bạn không cần "context" để truy cập Controller / Blocs của mình thông qua một InheritedWidget, vì vậy bạn hoàn toàn tách rời presentation logic và business logic ra khỏi lớp trực quan của mình. Bạn không cần phải đưa các Controller / Models / Blocs vào sơ đồ widget của mình thông qua `MultiProvider`, vì GetX sử dụng tính năng nạp dependency của riêng nó, tách hoàn toàn DI khỏi chế độ xem của nó.
Với GetX, bạn biết nơi tìm từng tính năng ứng dụng của mình, với cơ chế clean code theo mặc định. Ngoài việc giúp bảo trì dễ dàng, GetX giúp việc chia sẻ các mô-đun trở thành khả thi trong Flutter.
BLoC là điểm khởi đầu để tổ chức code trong Flutter, nó tách biệt business logic ra khỏi lớp trực quan hóa (visualization). GetX nảy sinh từ điều này, không chỉ tách biệt presentation logic mà còn cả business logic. Nạp dependency bổ sung và route cũng được tách ra và lớp dữ liệu cũng biến mất. Bạn sẽ biết mọi thứ ở đâu và sẽ hình dung tất cả những điều này dễ hơn cả xây dựng chương trình "Hello World".
GetX là cách dễ nhất, thiết thực và có thể mở rộng để xây dựng các ứng dụng hiệu suất cao với Flutter SDK. GetX chứa đựng một hệ sinh thái rộng lớn xung quanh nó hoạt động hoàn hảo cùng nhau, rất dễ dàng cho người mới bắt đầu và nó chính xác cho các chuyên gia. Nó an toàn, ổn định, luôn cập nhật và cung cấp một loạt các API được tích hợp sẵn mà không có trong Flutter SDK mặc định.
- GetX không cồng kềnh và có vô số tính năng cho phép bạn bắt đầu lập trình mà không cần lo lắng về bất cứ điều gì. Đặc biệt, nó cho phép mỗi tính năng này nằm trong các vùng chứa riêng biệt và chỉ được bắt đầu sau khi sử dụng. Nếu bạn chỉ sử dụng phần quản lý state của GetX thì sẽ chỉ có quản lý state được sử dụng. Nếu bạn chỉ sử dụng route, thì GetX không biên dịch phần quản lý state.
- GetX có một hệ sinh thái khổng lồ, một cộng đồng lớn, một số lượng lớn cộng tác viên và sẽ được duy trì miễn là Flutter còn tồn tại. GetX có khả năng chạy cùng một mã (code) trên Android, iOS, Web, Mac, Linux, Windows và trên máy chủ của bạn.
**Bạn hoàn toàn có thể sử dụng lại mã của mình trên frontend qua backend với [Get Server](https://github.com/jonataslaw/get_server)**.
**Ngoài ra, toàn bộ quá trình phát triển có thể hoàn toàn tự động, cả trên máy chủ và frontend với [Get CLI](https://github.com/jonataslaw/get_cli)**.
**Ngoài ra, nhằm tăng thêm năng suất của bạn, chúng tôi hỗ trợ
[tiện ích trên VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)[tiện ích cho Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**
# Cài Đặt
Thêm Get vào file pubspec.yaml:
```yaml
dependencies:
get:
```
Import get vào file cần sử dụng:
```dart
import 'package:get/get.dart';
```
# Counter App với GetX
Dự án "counter" được tạo theo mặc định trên dự án mới trên Flutter có hơn 100 dòng (có comments). Để thể hiện sức mạnh của Get, tôi sẽ trình bày cách tạo "counter" thay đổi trạng thái với mỗi lần nhấp, chuyển đổi giữa các trang và chia sẻ trạng thái giữa các màn hình, tất cả đều theo cách có tổ chức, tách biệt logic nghiệp vụ khỏi chế độ xem, CHỈ VỚI 26 DÒNG!
- Bước 1:
Thêm "Get" trước MaterialApp, nó sẽ thành GetMaterialApp
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
- Chú ý: điều này không sửa đổi MaterialApp của Flutter, GetMaterialApp không phải là MaterialApp được sửa đổi, nó chỉ là một Widget được tạo trước với MaterialApp mặc định là child. Bạn có thể cấu hình điều này theo cách thủ công, nhưng nó chắc chắn là không cần thiết. GetMaterialApp sẽ tạo các route, đưa chúng vào, đưa bản dịch, đưa mọi thứ bạn cần để điều hướng route. Nếu bạn chỉ sử dụng Get để quản lý trạng thái hoặc quản lý phụ thuộc, thì không cần thiết phải sử dụng GetMaterialApp. Tóm lại, GetMaterialApp chỉ cần thiết cho các route, snacksbar, internationalization, bottomSheets, Dialog và các APIs cấp cao liên quan đến route và không có "context".
- Chú ý²: Một lần nữa, bước này chỉ cần thiết nếu bạn sử dụng quản lý route (`Get.to ()`, `Get.back ()`, v.v.). Nếu bạn không sử dụng nó thì không cần thực hiện bước 1
- Bước 2:
Tạo lớp business logic của bạn và đặt tất cả các biến (variables), hàm (function) và controller bên trong nó.
Bạn có thể làm cho bất kỳ biến nào có thể quan sát được đơn giản bằng cách sử dụng ".obs".
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
- Bước 3:
Tạo widget của bạn, sử dụng StatelessWidget và tiết kiệm RAM, với Get, bạn có thể không cần sử dụng StatefulWidget nữa.
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Instantiate your class using Get.put() to make it available for all "child" routes there.
final Controller c = Get.put(Controller());
return Scaffold(
// Use Obx(()=> to update Text() whenever count is changed.
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// You can ask Get to find a Controller that is being used by another page and redirect you to it.
final Controller c = Get.find();
@override
Widget build(context){
// Access the updated count variable
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
Kết quả:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
Đây là một dự án đơn giản nhưng nó đã cho thấy rõ sức mạnh của Get. Khi dự án của bạn phát triển, sự khác biệt này sẽ trở nên đáng kể hơn.
Get được thiết kế để làm việc với các nhóm, nhưng nó làm cho công việc của một nhà phát triển cá nhân trở nên đơn giản.
Cải thiện thời gian, giao mọi thứ đúng hạn mà không làm giảm hiệu suất. Get không dành cho tất cả mọi người, nhưng nếu bạn đã xác định gắn với Get, Get sẽ "get" bạn!
# Tam Trụ
## Quản lý State
Get có 2 cách quản lý trạng thái (state managers) khác nhau : quản lý trạng thái đơn giản (chúng ta gọi nó là GetBuilder) và quản lý trạng thái phản ứng (the reactive state manager) (GetX/Obx).
### Quản lý Reactive State
Lập trình phản ứng (reactive programming) có thể khiến nhiều người xa lánh vì nó được cho là phức tạp. GetX biến lập trình phản ứng thành một thứ khá đơn giản:
- Bạn sẽ không cần tạo StreamControllers.
- Bạn sẽ không cần tạo StreamBuilder cho mỗi biến.
- Bạn sẽ không cần tạo một lớp (class) cho mỗi trạng thái.
- Bạn sẽ không cần tạo get cho một giá trị ban đầu.
- Bạn sẽ không cần sử dụng trình tạo mã.
Lập trình phản ứng với Get dễ dàng như sử dụng setState.
Hãy tưởng tượng rằng bạn có một biến tên và muốn rằng mỗi khi bạn thay đổi nó, tất cả các widget sử dụng nó sẽ được tự động thay đổi.
Đây là biến đếm của bạn:
```dart
var name = 'Jonatas Borges';
```
Để nó có thể được lắng nghe, bạn chỉ cần thêm ".obs" ở cuối:
```dart
var name = 'Jonatas Borges'.obs;
```
Và trong UI, khi bạn muốn hiển thị giá trị đó và cập nhật màn hình bất cứ khi nào giá trị thay đổi, chỉ cần thực hiện điều này:
```dart
Obx(() => Text("${controller.name}"));
```
Thế thôi. Chỉ là _thế_ thôi người ơi~.
### Thêm thông tin về Quản lý state
**Xem thông tin cụ thể tại [đây](./documentation/en_US/state_management.md). Tại đó, bạn có thể tham khảo ví dụ và so sánh sự khác nhau giữa quản lý state cơ bản và quản lý state reactive**
Bạn sẽ hình dung được sức mạnh của GetX.
## Quản lý route
Nếu bạn chỉ sử dụng routes/snackbars/dialogs/bottomsheets không có context, GetX là lựa chọn số 2 trừ 1, nhìn đây:
Thêm "Get" trước MaterialApp, nó sẽ biến thành GetMaterialApp
```dart
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
```
Di chuyển tới màn hình mới:
```dart
Get.to(NextScreen());
```
Di chuyển tới màn hình mới theo tên. Xem thêm tại [đây](./documentation/en_US/route_management.md#navigation-with-named-routes)
```dart
Get.toNamed('/details');
```
Để đóng snackbars, dialogs, bottomsheets, hay bất kì thứ gì, bạn có thể xài cái này để thay Navigator.pop(context);
```dart
Get.back();
```
Đi đến màn hình kế tiếp và bỏ luôn màn hình cũ (thường dùng cho màn hình giới thiệu, màn hình đăng nhập, etc.)
```dart
Get.off(NextScreen());
```
Đi đến màn hình kế tiếp và đóng tất cả các routes (hữu dụng cho shopping cart, polls, và tests)
```dart
Get.offAll(NextScreen());
```
Bạn có thấy nãy giờ chúng ta không sử dụng từ khóa "context"? Đây chính là thang điểm 9 + 1 của quản lý route ở Get. Với điểm mạnh trên, bạn có thể thao tác bất cứ đâu, kể cả trong controller class.
### Thêm thông tin về quản lý route
**Get hoạt động được với named routes và cũng cung cấp cách điều khiển ở cấp thấp (lower-level control) cho routes của bạn! Tài liệu chi tiết tại [đây](./documentation/en_US/route_management.md)**
## Quản lý dependency
Get hỗ trợ tính năng giúp bạn lấy class như Bloc hoặc Controller chỉ với 1 dòng, không cần Provider context hay InheritedWidget:
```dart
Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
```
- Chú ý: Nếu bạn dùng Get's State Manager, hãy chú ý đến việc bindings API, có thể giúp dễ dàng kết nối view đến controller.
Thay vì khởi tạo class của bạn trong class bạn đang sử dụng, bạn đang khởi tạo nó trong phiên bản Get, điều này sẽ làm cho nó có sẵn trên toàn bộ Ứng dụng của bạn.
Vì vậy, bạn có thể sử dụng bộ điều khiển (hoặc Bloc) của mình một cách bình thường
**Mẹo:** quản lý dependency của Get được tách ra khỏi các phần khác của package, vì vậy, ví dụ: nếu ứng dụng của bạn đã sử dụng 1 trình quản lý trạng thái (bất kỳ cái nào, không quan trọng), bạn không cần phải viết lại tất cả, bạn có thể sử dụng nạp dependency của Get vô lo
```dart
controller.fetchApi();
```
Hãy tưởng tượng rằng bạn đã điều hướng qua nhiều route và bạn cần dữ liệu bị còn sót trong controller của mình, bạn sẽ cần một trình quản lý dependency kết hợp với Provider hoặc Get_it, đúng không? Với Get, sử dụng Get để "find" cho controller, bạn sẽ hoàn toàn độc lập:
```dart
Controller controller = Get.find();
//Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllers instantiated, Get will always give you the right controller.
```
Và sau đó, bạn sẽ có thể khôi phục dữ liệu controller của mình đã lấy được ở đó:
```dart
Text(controller.textFromApi);
```
### Thêm thông tin về quản lý dependency
**Xem thêm tại [đây](./documentation/en_US/dependency_management.md)**
# Utils
## Internationalization
### Dịch thuật
Các bản dịch được lưu giữ như một bản đồ từ điển (dictionary map) key-value đơn giản.
Để thêm các bản dịch tùy chỉnh, hãy tạo một class và kế thừa (extend) từ `Translation`.
```dart
import 'package:get/get.dart';
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello World',
},
'de_DE': {
'hello': 'Hallo Welt',
}
};
}
```
#### Sử dụng bản dịch thuật
Chỉ cần thêm `.tr` vào key được chỉ định và nó sẽ được dịch, sử dụng giá trị hiện tại của` Get.locale` và `Get.fallbackLocale`.
```dart
Text('title'.tr);
```
#### Sử dụng bản dịch thuật với số ít và số nhiều
```dart
var products = [];
Text('singularKey'.trPlural('pluralKey', products.length, Args));
```
#### Sử dụng bản dịch với tham số (parameters)
```dart
import 'package:get/get.dart';
Map<String, Map<String, String>> get keys => {
'en_US': {
'logged_in': 'logged in as @name with email @email',
},
'es_ES': {
'logged_in': 'iniciado sesión como @name con e-mail @email',
}
};
Text('logged_in'.trParams({
'name': 'Jhon',
'email': 'jhon@example.com'
}));
```
### Locales
Chuyển các tham số (parameters) cho `GetMaterialApp` để xác định ngôn ngữ và bản dịch.
```dart
return GetMaterialApp(
translations: Messages(), // your translations
locale: Locale('en', 'US'), // translations will be displayed in that locale
fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.
);
```
#### Đổi locale
Gọi `Get.updateLocale (locale)` 'để cập nhật ngôn ngữ. Các bản dịch sau đó sẽ tự động sử dụng ngôn ngữ mới.
```dart
var locale = Locale('en', 'US');
Get.updateLocale(locale);
```
#### System locale
Để đọc system locale, sử dụng `Get.deviceLocale`.
```dart
return GetMaterialApp(
locale: Get.deviceLocale,
);
```
## Đổi chủ đề (Theme)
Vui lòng không sử dụng bất kỳ Widget con nào cấp cao hơn `GetMaterialApp` để cập nhật nó. Điều này có thể kích hoạt các key trùng lặp. Rất nhiều người đã quen với cách tiếp cận thời tiền sử là tạo tiện ích "ThemeProvider" chỉ để thay đổi chủ đề ứng dụng của bạn và điều này KHÔNG cần thiết với ** GetX ™ **.
Bạn có thể tạo chủ đề tùy chỉnh của mình và chỉ cần thêm nó vào trong `Get.changeTheme` mà không cần bất kỳ điều gì khác:
```dart
Get.changeTheme(ThemeData.light());
```
Nếu bạn muốn tạo một cái gì đó giống như một nút thay đổi Theme với `onTap`, bạn có thể kết hợp hai API ** GetX ™ ** cho điều đó:
- Api kiểm tra xem `Theme` tối có đang được sử dụng hay không.
-`Theme` sẽ thay đổi API, bạn sử dụng với `onPressed`:
```dart
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
```
Khi bật `.darkmode`, nó sẽ chuyển _light theme_, và khi bật _light theme_ , nó sẽ chuyển _dark theme_.
## GetConnect
GetConnect tạo giao thức tới http hoặc websockets
### Cấu hình mặc định
Đơn giản, bạn có thể kế thừa (extend) từ GetConnect và sử dụng các phương thức GET/POST/PUT/DELETE/SOCKET khi giao tiếp với Rest API hoặc websockets.
```dart
class UserProvider extends GetConnect {
// Get request
Future<Response> getUser(int id) => get('http://youapi/users/$id');
// Post request
Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
// Post request with File
Future<Response<CasesModel>> postCases(List<int> image) {
final form = FormData({
'file': MultipartFile(image, filename: 'avatar.png'),
'otherFile': MultipartFile(image, filename: 'cover.png'),
});
return post('http://youapi/users/upload', form);
}
GetSocket userMessages() {
return socket('https://yourapi/users/socket');
}
}
```
### Cấu hình tùy chỉnh
GetConnect có khả năng tùy chỉnh cao Bạn có thể xác định Url chính như answers, modifiers như request, xác địng authenticator và thậm chí số lần thử mà nó sẽ cố gắng authenticate, ngoài việc cung cấp khả năng xác định bộ giải mã chuẩn sẽ chuyển đổi tất cả các request của bạn thành Model mà không cần bất kỳ cấu hình bổ sung nào.
```dart
class HomeProvider extends GetConnect {
@override
void onInit() {
// All request will pass to jsonEncode so CasesModel.fromJson()
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.baseUrl = 'https://api.covid19api.com';
// baseUrl = 'https://api.covid19api.com'; // It define baseUrl to
// Http and websockets if used with no [httpClient] instance
// It's will attach 'apikey' property on header from all requests
httpClient.addRequestModifier((request) {
request.headers['apikey'] = '12345678';
return request;
});
// Even if the server sends data from the country "Brazil",
// it will never be displayed to users, because you remove
// that data from the response, even before the response is delivered
httpClient.addResponseModifier<CasesModel>((request, response) {
CasesModel model = response.body;
if (model.countries.contains('Brazil')) {
model.countries.remove('Brazilll');
}
});
httpClient.addAuthenticator((request) async {
final response = await get("http://yourapi/token");
final token = response.body['token'];
// Set the header
request.headers['Authorization'] = "$token";
return request;
});
//Autenticator will be called 3 times if HttpStatus is
//HttpStatus.unauthorized
httpClient.maxAuthRetries = 3;
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
}
```
## GetPage Middleware
GetPage hiện có thuộc tính mới lấy danh sách GetMiddleWare và chạy chúng theo thứ tự cụ thể.
**Chú ý**: Khi GetPage có Middleware (phần trung gian), tất cả các children của trang này sẽ tự động có cùng middlewares.
### Ưu tiên
Thứ tự ưu tiên của Middlewares có thể đặt như sau trong GetMiddleware.
```dart
final middlewares = [
GetMiddleware(priority: 2),
GetMiddleware(priority: 5),
GetMiddleware(priority: 4),
GetMiddleware(priority: -8),
];
```
và chúng sẽ chạy như thế này **-8 => 2 => 4 => 5**
### Chuyển hướng
Khi bạn muốn tìm kiếm trang của route được gọi, function (hàm) sẽ khởi động. Kết quả là phải có RouteSettings để chuyển hướng đến. Hoặc cung cấp cho nó null và chuyển hướng không xảy ra.
```dart
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login')
}
```
### onPageCalled
Khi bạn gọi một trang trước mọi thứ được tạo, hàm này sẽ khởi động và
bạn có thể sử dụng nó để thay đổi điều gì đó về trang hoặc tạo cho nó một trang mới
```dart
GetPage onPageCalled(GetPage page) {
final authService = Get.find<AuthService>();
return page.copyWith(title: 'Welcome ${authService.UserName}');
}
```
### OnBindingsStart
Hàm này sẽ khởi động ngay trước khi Bindings diễn ra và bạn có thể thay đổi Bindings cho trang này.
```dart
List<Bindings> onBindingsStart(List<Bindings> bindings) {
final authService = Get.find<AuthService>();
if (authService.isAdmin) {
bindings.add(AdminBinding());
}
return bindings;
}
```
### OnPageBuildStart
Hàm này sẽ khởi động ngay sau khi Bindings diễn ra. Ở đây, bạn có thể làm thứ gì đó sau khi bạn tạo Bindings và trước khi tạo trang widget.
```dart
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
print('bindings are ready');
return page;
}
```
### OnPageBuilt
Hàm này sẽ khởi động ngay sau khi GetPage.page được gọi và sẽ cho bạn kết quả của hàm và lấy widget được hiển thị.
### OnPageDispose
Function này sẽ khởi động ngay sau khi hủy bỏ tất cả các đối tượng liên quan (Controller, views, ...) của trang.
## APIs nâng cao khác
```dart
// give the current args from currentScreen
Get.arguments
// give name of previous route
Get.previousRoute
// give the raw route to access for example, rawRoute.isFirst()
Get.rawRoute
// give access to Routing API from GetObserver
Get.routing
// check if snackbar is open
Get.isSnackbarOpen
// check if dialog is open
Get.isDialogOpen
// check if bottomsheet is open
Get.isBottomSheetOpen
// remove one route.
Get.removeRoute()
// back repeatedly until the predicate returns true.
Get.until()
// go to next route and remove all the previous routes until the predicate returns true.
Get.offUntil()
// go to next named route and remove all the previous routes until the predicate returns true.
Get.offNamedUntil()
//Check in what platform the app is running
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//Check the device type
GetPlatform.isMobile
GetPlatform.isDesktop
//All platforms are supported independently in web!
//You can tell if you are running inside a browser
//on Windows, iOS, OSX, Android, etc.
GetPlatform.isWeb
// Equivalent to : MediaQuery.of(context).size.height,
// but immutable.
Get.height
Get.width
// Gives the current context of the Navigator.
Get.context
// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.
Get.contextOverlay
// Chí ú: Nếu bạn dùng cái này, nhớ đặtt. thànhnce you
// have access to context in any place of your UI, you can use it anywhere in the UI code
// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.
context.width
context.height
// Gives you the power to define half the screen, a third of it and so on.
// Useful for responsive applications.
// param dividedBy (double) optional - default: 1
// param reducedBy (double) optional - default: 0
context.heightTransformer()
context.widthTransformer()
/// Similar to MediaQuery.of(context).size
context.mediaQuerySize()
/// Similar to MediaQuery.of(context).padding
context.mediaQueryPadding()
/// Similar to MediaQuery.of(context).viewPadding
context.mediaQueryViewPadding()
/// Similar to MediaQuery.of(context).viewInsets;
context.mediaQueryViewInsets()
/// Similar to MediaQuery.of(context).orientation;
context.orientation()
/// Check if device is on landscape mode
context.isLandscape()
/// Check if device is on portrait mode
context.isPortrait()
/// Similar to MediaQuery.of(context).devicePixelRatio;
context.devicePixelRatio()
/// Similar to MediaQuery.of(context).textScaleFactor;
context.textScaleFactor()
/// Get the shortestSide from screen
context.mediaQueryShortestSide()
/// True if width be larger than 800
context.showNavbar()
/// True if the shortestSide is smaller than 600p
context.isPhone()
/// True if the shortestSide is largest than 600p
context.isSmallTablet()
/// True if the shortestSide is largest than 720p
context.isLargeTablet()
/// True if the current device is Tablet
context.isTablet()
/// Returns a value<T> according to the screen size
/// can give value for:
/// watch: if the shortestSide is smaller than 300
/// mobile: if the shortestSide is smaller than 600
/// tablet: if the shortestSide is smaller than 1200
/// desktop: if width is largest than 1200
context.responsiveValue<T>()
```
### Cấu hình thủ công và cài đặt chung tuỳ chọn
GetMaterialApp configures everything for you, but if you want to configure Get manually.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
```
Bạn cũng sẽ có thể dùng Middleware của riêng bạn trong `GetObserver`, điều này không ảnh hưởng những thứ khác.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // Here
],
);
```
Bạn có thể tạo _Global Settings_ cho `Get`. Chỉ cần thêm `Get.config` vào code của bạn trước khi đẩy (push) bất cứ route nào.
Hoặc làm nó trực tiếp trong `GetMaterialApp` của bạn.
```dart
GetMaterialApp(
enableLog: true,
defaultTransition: Transition.fade,
opaqueRoute: Get.isOpaqueRouteDefault,
popGesture: Get.isPopGestureEnable,
transitionDuration: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino
)
```
Bạn có thể tự chọn chuyển hướng tất cả logging messages từ `Get`.
Nếu bạn muốn sử dụng logging package ưa thích của riêng bạn, và muốn chụp lại những logs đó:
```dart
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// pass the message to your favourite logging package here
// please note that even if enableLog: false log messages will be pushed in this callback
// you get check the flag if you want through GetConfig.isLogEnable
}
```
### Local State Widgets
Các Widget này cho phép bạn quản lý một giá trị duy nhất và giữ trạng thái tạm thời và cục bộ.
Chúng ta có các hướng đi cho Reactive và Simple.
Ví dụ: bạn có thể sử dụng chúng để chuyển đổi văn bản tối nghĩa trong một `TextField`, có thể tạo một widget
Expandable Panel tùy chỉnh hoặc có thể sửa đổi chỉ mục hiện tại trong `BottomNavigationBar` trong khi thay đổi nội dung
bên trong một `Scaffold`.
#### ValueBuilder
Đơn giản hóa của `StatefulWidget` hoạt động với lệnh gọi lại` .setState` nhận giá trị cập nhật.
```dart
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )
),
// if you need to call something outside the builder method.
onUpdate: (value) => print("Value updated: $value"),
onDispose: () => print("Widget unmounted"),
),
```
#### ObxValue
Tương tự như [`ValueBuilder`](#valuebuilder), nhưng đây là phiên bản Reactive, bạn kèm một lệnh Rx (nhớ cái .obs không?) và nó cập nhật tự động ... hay chưa?
```dart
ObxValue((data) => Switch(
value: data.value,
onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,
),
false.obs,
),
```
## Mẹo hữu ích
`.obs` observable (variable có thể quan sát được) (còn được gọi là loại _Rx_) có nhiều phương thức và toán tử bên trong.
> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!
> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code
> looks cleaner, but:
```dart
var message = 'Xin Chào'.obs;
print( 'Message "$message" has Type ${message.runtimeType}');
```
Ngay cả khi `message` _prints_ giá trị String, thì kiểu của nó lại là ** RxString **!
Vì vậy, bạn không thể thực hiện `message.substring (0, 4) '. Bạn phải truy cập vào `value`thực bên trong _observable_: Cách được sử dụng nhiều nhất là`.value`, nhưng, bạn có biết rằng bạn cũng có thể sử dụng ...
```dart
final name = 'GetX'.obs;
// only "updates" the stream, if the value is different from the current one.
name.value = 'Hey';
// All Rx properties are "callable" and returns the new value.
// but this approach does not accepts `null`, the UI will not rebuild.
name('Hello');
// is like a getter, prints 'Hello'.
name() ;
/// numbers:
final count = 0.obs;
// You can use all non mutable operations from num primitives!
count + 1;
// Watch out! this is only valid if `count` is not final, but var
count += 1;
// You can also compare against values:
count > 2;
/// booleans:
final flag = false.obs;
// switches the value between true/false
flag.toggle();
/// all types:
// Sets the `value` to null.
flag.nil();
// All toString(), toJson() operations are passed down to the `value`
print( count ); // calls `toString()` inside for RxInt
final abc = [0,1,2].obs;
// Converts the value to a json Array, prints RxList
// Json is supported by all Rx types!
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap, RxList and RxSet are special Rx types, that extends their native types.
// but you can work with a List as a regular list, although is reactive!
abc.add(12); // pushes 12 to the list, and UPDATES the stream.
abc[3]; // like Lists, reads the index 3.
// equality works with the Rx and the value, but hashCode is always taken from the value
final number = 12.obs;
print( number == 12 ); // prints > true
/// Custom Rx Models:
// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age years old';
}
final user = User(name: 'Khang', last: 'Huỳnh', age: 33).obs;
// `user` is "reactive", but the properties inside ARE NOT!
// So, if we change some variable inside of it...
user.value.name = 'Kaiser';
// The widget will not rebuild!,
// `Rx` don't have any clue when you change something inside user.
// So, for custom classes, we need to manually "notify" the change.
user.refresh();
// or we can use the `update()` method!
user.update((value){
value.name='Kaiser';
});
print( user );
```
## StateMixin
Một cách khác để xử lý trạng thái `UI` của bạn là sử dụng`StateMixin <T>`.
Để triển khai nó, hãy sử dụng dấu `with` để thêm`StateMixin <T>` vào bộ điều khiển (controller) của bạn cho phép tích hợp kèm mô hình T.
```dart
class Controller extends GetController with StateMixin<User>{}
```
Phương thức `change()` thay đổi trạng thái bất cứ khi nào chúng ta muốn.
Chỉ cần chuyển dữ liệu và trạng thái theo cách này:
```dart
change(data, status: RxStatus.success());
```
RxStatus cho phép những trang thái này:
```dart
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');
```
Để biểu hiện nó trên UI, sử dụng:
```dart
class OtherClass extends GetView<Controller> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.obx(
(state)=>Text(state.name),
// here you can put your custom loading indicator, but
// by default would be Center(child:CircularProgressIndicator())
onLoading: CustomLoadingIndicator(),
onEmpty: Text('No data found'),
// here also you can set your own error widget, but by
// default will be an Center(child:Text(error))
onError: (error)=>Text(error),
),
);
}
```
#### GetView
Widget này là bảo bối của GetX, rất đơn giản, nhưng rất hữu ích!
Là một Widget `const Stateless` có getter` controller` cho một `Controller` đã đăng ký, chỉ vậy thôi người ơi~.
```dart
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
// ALWAYS remember to pass the `Type` you used to register your controller!
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // just call `controller.something`
);
}
}
```
#### GetResponsiveView
Mở rộng tiện ích này để xây dựng chế độ responsive.
Widget này chứa thuộc tính `screen` có tất cả
thông tin về kích thước và loại màn hình.
##### Hướng dẫn sử dụng trước khi dùng
Bạn có hai lựa chọn để xây dựng nó.
- với phương thức `builder` bạn trả về tiện ích con để xây dựng.
- với các phương thức `desktop`,` tablet`, `phone`,` watch`. cụ thể, các phương thức này sẽ tạo các loại màn hình khớp với ngữ cảnh khi màn hình là [ScreenType.Tablet] thì phương thức `tablet` sẽ được tạo ra và cứ như vậy.
**Chú ý:** Nếu bạn dùng cái này, nhớ đặt `alwaysUseBuilder` thành `false`
Với thuộc tính `settings` bạn có thể đặt chiều dài tối thiểu cho các loại màn hình.
![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
Code to this screen
[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
#### GetWidget
Hầu hết mọi người không biết gì về Widget này, hoặc hoàn toàn nhầm lẫn về cách sử dụng nó.
Trường hợp sử dụng rất hiếm, nhưng rất cụ thể: Nó `caches` một Bộ điều khiển.
Bởi vì _cache_ không thể là một `const Stateless`.
> Vậy khi nào mình cần cache bộ điều khiển (controller)?
Nếu sử dụng, bạn sẽ dùng cái này **GetX**: `Get.create()`.
`Get.create(()=>Controller())` sẽ tạo một `Controller` với mỗi lần gọi `Get.find<Controller>()`,
Đó là nơi mà `GetWidget` tỏa sáng ... chẳng hạn như bạn có thể sử dụng nó, để giữ một danh sách các mục Todo. Vì vậy, nếu widget được "xây dựng lại", nó sẽ giữ nguyên phiên bản controller.
#### GetxService
Class này giống như một `GetxController`, nó chia sẻ cùng một vòng đời (`onInit ()`,`onReady ()`,`onClose ()`).
Nhưng không có "logic" bên trong của nó. Nó chỉ thông báo cho ** GetX ** Hệ thống Nạp Dependency rằng class con này ** không thể ** bị xóa khỏi bộ nhớ.
Vì vậy, rất hữu ích để giữ cho "Service" của bạn luôn có thể truy cập và hoạt động với `Get.find ()`. Giống:
`ApiService`,` StorageService`, `CacheService`.
```dart
Future<void> main() async {
await initServices(); /// AWAIT SERVICES INITIALIZATION.
runApp(SomeApp());
}
/// Is a smart move to make your Services intiialize before you run the Flutter app.
/// as you can control the execution flow (maybe you need to load some Theme configuration,
/// apiKey, language defined by the User... so load SettingService before running ApiService.
/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.
void initServices() async {
print('starting services ...');
/// Here is where you put get_storage, hive, shared_pref initialization.
/// or moor connection, or whatever that's async.
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
```
Cách duy nhất để thực sự xóa một `GetxService`, là với `Get.reset ()` giống như cách thức "Khởi động nóng" ứng dụng của bạn. Vì vậy, hãy nhớ rằng, nếu bạn cần sự tồn tại tuyệt đối của một class trong vòng đời tồn tại của nó trong ứng dụng của bạn, hãy sử dụng `GetxService`.
# Thay đổi đột phá 2.0
1- Rx types:
| Before | After |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RxController và GetBuilder bây giờ đã hợp nhất, bạn không cần phải ghi nhớ bộ điều khiển nào bạn muốn sử dụng, chỉ cần sử dụng GetxController, nó sẽ hoạt động để quản lý trạng thái đơn giản và reactive.
2- NamedRoutes
Before:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
Now:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
```
Tại sao lại thay đổi?
Thông thường, có thể cần phải quyết định trang nào sẽ được hiển thị từ một tham số hoặc mã thông báo đăng nhập, cách tiếp cận trước đây không linh hoạt, vì nó không cho phép điều này.
Việc chèn trang vào một hàm đã làm giảm đáng kể mức tiêu thụ RAM, vì các tuyến sẽ không được cấp phát trong bộ nhớ kể từ khi ứng dụng được khởi động và nó cũng cho phép thực hiện kiểu tiếp cận này:
```dart
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
# Tại sao lại dùng GetX
1- Nhiều lần sau khi cập nhật Flutter, nhiều package của bạn sẽ bị hỏng. Đôi khi lỗi biên dịch code xảy ra, lỗi thường xuất hiện mà vẫn không có câu trả lời; và, chúng ta, nhà phát triển, cần biết lỗi đến từ đâu, theo dõi lỗi, chỉ sau đó cố gắng mở một vấn đề trong kho lưu trữ tương ứng và xem vấn đề của nó đã được giải quyết. Tập trung các tài nguyên chính để phát triển (Quản lý state, dependency và route), cho phép bạn thêm một gói duy nhất vào pubspec của mình và bắt đầu hoạt động. Sau khi cập nhật Flutter, điều duy nhất bạn cần làm là cập nhật Get dependency và bắt đầu làm việc. Get cũng giải quyết các vấn đề tương thích. Có bao nhiêu lần một phiên bản của một gói không tương thích với phiên bản của gói khác, vì một gói sử dụng phần phụ thuộc trong một phiên bản và gói kia trong phiên bản khác? Đây cũng không phải là vấn đề đáng lo ngại khi sử dụng Get, vì mọi thứ đều nằm trong cùng một gói và hoàn toàn tương thích.
2- Flutter dễ học, Flutter siêu phàm, nhưng Flutter vẫn có một số bản soạn sẵn có thể không mong muốn đối với hầu hết các nhà phát triển, chẳng hạn như `Navigator.of (context) .push (context, builder [...] '. Get đơn giản hóa việc phát triển. Thay vì viết 8 dòng mã chỉ để gọi một tuyến đường, bạn chỉ cần làm điều đó: `` Get.to (Home ()) 'và bạn đã hoàn tất, bạn sẽ chuyển sang trang tiếp theo. Các url web động là một điều thực sự khó khăn để làm với Flutter hiện tại và điều đó với GetX đơn giản đến đần độn :). Quản lý trạng thái trong Flutter và quản lý các phần phụ thuộc cũng là điều tạo ra nhiều cuộc thảo luận, vì có hàng trăm mẫu trong pub (Dart package website). Nhưng không có gì dễ dàng bằng việc thêm ".obs" ở cuối biến của bạn, và đặt tiện ích của bạn bên trong Obx, và thế là xong, tất cả các cập nhật cho biến đó sẽ được tự động cập nhật trên màn hình.
3- Dễ dàng mà không phải lo lắng về hiệu suất. Hiệu suất của Flutter đã đáng kinh ngạc rồi, nhưng hãy tưởng tượng rằng bạn sử dụng trình quản lý state và trình định vị để phân phối các Blocs / stores / controllers / v.v. của bạn. Bạn sẽ phải gọi thủ công loại trừ sự phụ thuộc khi bạn không cần đến chúng. Nhưng bạn đã bao giờ nghĩ chỉ cần sử dụng bộ điều khiển của mình và khi nó không còn được ai sử dụng nữa, nó sẽ đơn giản được xóa khỏi bộ nhớ? Đó là những gì GetX làm. Với SmartManagement, mọi thứ không được sử dụng sẽ được xóa khỏi bộ nhớ và bạn không phải lo lắng về bất cứ điều gì ngoài lập trình. Bạn sẽ được đảm bảo rằng bạn đang sử dụng các nguồn tài nguyên cần thiết tối thiểu mà thậm chí không cần tạo ra một logic nào cho việc này.
4- Tách khỏi thực tế. Bạn có thể đã nghe đến khái niệm "tách khung nhìn (view) khỏi business logic". Đây không phải là đặc thù của BLoC, MVC, MVVM và bất kỳ tiêu chuẩn nào khác trên thị trường đều có khái niệm này. Tuy nhiên, khái niệm này thường có thể được giảm thiểu trong Flutter do việc sử dụng ngữ cảnh (context).
Nếu bạn cần ngữ cảnh để tìm một InheritedWidget, bạn cần nó trong dạng xem hoặc chuyển ngữ cảnh theo tham số. Tôi đặc biệt thấy giải pháp này rất chán đời; hơn nữa, để làm việc theo nhóm, chúng tôi sẽ luôn phụ thuộc vào business logic của View. GetX không chính thống với cách tiếp cận tiêu chuẩn và mặc dù nó không cấm hoàn toàn việc sử dụng StatefulWidgets, InitState, v.v., nhưng nó luôn có một cách tiếp cận tương tự có thể rõ ràng hơn. Controller có vòng đời và khi bạn cần thực hiện yêu cầu APIREST chẳng hạn, bạn độc lập với View. Bạn có thể sử dụng onInit để bắt đầu cuộc gọi http và khi dữ liệu đến, các biến sẽ được điền. Vì GetX hoạt động hoàn toàn reactive (đó là sự thực và hoạt động theo luồng), khi các mục được lấp đầy, tất cả tiện ích con sử dụng biến đó sẽ được cập nhật tự động trong View. Điều này cho phép những người có chuyên môn về UI chỉ làm việc với các widget và không phải gửi bất kỳ thứ gì đến logic nghiệp vụ ngoài các sự kiện của người dùng (như nhấp vào nút), trong khi những người làm việc với logic nghiệp vụ sẽ được tự do tạo và kiểm tra logic nghiệp vụ riêng.
Thư viện này sẽ luôn được cập nhật và triển khai các tính năng mới. Hãy thoải mái đưa ra các bài PR và đóng góp cho chúng.
# Cộng đồng
## Kênh Cộng đồng
GetX có một cộng đồng rất tích cực và hữu ích. Nếu bạn có thắc mắc hoặc muốn được hỗ trợ về việc sử dụng khuôn khổ này, vui lòng tham gia các kênh cộng đồng của chúng tôi, câu hỏi của bạn sẽ được trả lời nhanh hơn và đó sẽ là nơi phù hợp nhất. Kho lưu trữ này dành riêng cho các vấn đề mở và yêu cầu tài nguyên, nhưng hãy thoải mái trở thành một phần của Cộng đồng GetX.
| **Slack** | **Discord** | **Telegram** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
## Cách cống hiến
_Bạn muốn đóng góp cho dự án? Chúng tôi sẽ tự hào giới thiệu bạn với tư cách là một trong những cộng tác viên của chúng tôi. Dưới đây là một số điểm mà bạn có thể đóng góp và làm cho Get (và Flutter) tốt hơn nữa._
- Giúp dịch readme sang các ngôn ngữ khác.
- Thêm tài liệu vào readme (rất nhiều chức năng của Get chưa được tài liệu hóa).
- Viết bài hoặc làm video dạy cách sử dụng Get (chúng sẽ được chèn vào Readme và trong tương lai trong Wiki của chúng tôi).
- Đưa ra các PR cho mã / bài kiểm tra.
- Bao gồm các chức năng mới.
Mọi đóng góp đều được hoan nghênh!
## Các bài báo và video
- [Flutter GetX EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Hướng dẫn bởi [Pesa Coder](https://github.com/UsamaElgendy).
- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Hướng dẫn bởi [Rod Brown](https://github.com/RodBr).
- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Quản lý route bởi Amateur Coder.
- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - Quản lý State video by Amateur Coder.
- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.
- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.
- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.
- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - Quản lý State by [Aachman Garg](https://github.com/imaachman).
- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Nạp dependency by [Aachman Garg](https://github.com/imaachman).
- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - Giới thiệu sơ lược về quản lý State and Navigation by Thad Carnevalli.
- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli.
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**Bahasa: Indonesia (file ini), [Inggris](README.md), [Urdu](README.ur-PK.md), [China](README.zh-cn.md), [Portugis (Brazil)](README.pt-br.md), [Spanyol](README-es.md), [Russia](README.ru.md), [Polandia](README.pl.md), [Korea](README.ko-kr.md), [French](README-fr.md)**
**Bahasa: Indonesia (file ini), [Inggris](README.md), [Orang Vietnam](README-vi.md), [Urdu](README.ur-PK.md), [China](README.zh-cn.md), [Portugis (Brazil)](README.pt-br.md), [Spanyol](README-es.md), [Russia](README.ru.md), [Polandia](README.pl.md), [Korea](README.ko-kr.md), [French](README-fr.md)**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
... ... @@ -498,7 +500,7 @@ middleware diatas akan dijalankan dengan urutan sebagai berikut **-8 => 2 => 4 =
Fungsi ini akan terpanggil ketika halaman dari route yang dipanggil sedang dicari. RouteSettings diperlukan untuk mengatur tujuan dari fungsi redirect. Atau berikan null jika tidak ingin ada redirect.
```dart
GetPage redirect( ) {
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login')
}
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)
[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
<a href="https://github.com/Solido/awesome-flutter">
<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" />
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
<div align="center">
**言語**
[![英語](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)
[![ベトナム語](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)
[![インドネシア語](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)
[![ウルドゥー語](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)
[![中国語](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)
[![ポルトガル語](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)
[![スペイン語](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)
[![ロシア語](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)
[![ポーランド語](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)
[![韓国語](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
[![フランス語](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
[![日本語](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README-ja.md)
</div>
- [Getとは](#Getとは)
- [インストール方法](#インストール方法)
- [GetXによるカウンターアプリ](#GetXによるカウンターアプリ)
- [三本柱](#三本柱)
- [状態管理](#状態管理)
- [リアクティブな状態管理](#リアクティブな状態管理)
- [状態管理に関する詳細ドキュメント](#状態管理に関する詳細ドキュメント)
- [Route管理](#Route管理)
- [Route管理に関する詳細ドキュメント](#Route管理に関する詳細ドキュメント)
- [依存オブジェクト管理](#依存オブジェクト管理)
- [依存オブジェクト管理に関する詳細ドキュメント](#依存オブジェクト管理に関する詳細ドキュメント)
- [ユーティリティ](#ユーティリティ)
- [多言語対応](#多言語対応)
- [翻訳ファイル](#翻訳ファイル)
- [翻訳ファイルの利用](#翻訳ファイルの利用)
- [ロケール](#ロケール)
- [ロケールの変更](#ロケールの変更)
- [システムのロケールを読み込む](#システムのロケールを読み込む)
- [Themeの変更](#Themeの変更)
- [GetConnect](#getconnect)
- [デフォルト設定](#デフォルト設定)
- [カスタム設定](#カスタム設定)
- [GetPageにミドルウェアを設定](#GetPageにミドルウェアを設定)
- [実行優先度](#実行優先度)
- [redirect](#redirect)
- [onPageCalled](#onpagecalled)
- [onBindingsStart](#onbindingsstart)
- [onPageBuildStart](#onpagebuildstart)
- [onPageBuilt](#onpagebuilt)
- [onPageDispose](#onpagedispose)
- [その他API](#その他API)
- [オプションのグローバル設定と手動設定](#オプションのグローバル設定と手動設定)
- [ローカルステートWidget](#ローカルステートWidget)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [お役立ちTIPS](#お役立ちTIPS)
- [StateMixin](#statemixin)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [使い方](#使い方])
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [テストの実行](#テストの実行)
- [mockitoやmocktailを使う場合](#mockitoやmocktailを使う場合)
- [Get.reset()](#Get.reset())
- [Get.testMode](#Get.testMode)
- [バージョン2.0からの破壊的変更](#バージョン2.0からの破壊的変更)
- [なぜGetXなのか](#なぜGetXなのか)
- [コミュニティ](#コミュニティ)
- [コミュニティチャンネル](#コミュニティチャンネル)
- [コントリビュート方法](#コントリビュート方法)
- [GetXに関する記事と動画](#GetXに関する記事と動画)
# Getとは
- GetXはFlutterのための超軽量でパワフルなソリューションです。高パフォーマンスな状態管理機能、インテリジェントな依存オブジェクト管理機能、そしてRoute管理機能の三本柱を軽量かつ実用的な形で組み合わせています。
- GetXは3つの基本原則を念頭に開発されています。 **【生産性、パフォーマンス、コードの分離性】** これらはライブラリ内のすべてのリソースに優先適用されている原則です。
- **パフォーマンス:** GetXは高いパフォーマンスと最小限のリソース消費を目標にしています。GetXはでは Stream および ChangeNotifier を利用しなくて済みます。
- **生産性:** GetXはシンプルで使い心地のいいシンタックスを採用しています。あなたの実現したい機能がどんなものであれ、GetXを使えばより簡単に実現できる方法が見つかるでしょう。開発にかかる時間を短縮し、あなたのアプリケーションのパフォーマンスを最大限引き出してくれます。
開発者はメモリリソースの管理に気を配るのが常です。しかしGetXでは、リソースが使用されていないときはメモリから削除されるのがデフォルト動作のため、過度に気にかける必要はありません。(逆にメモリに残しておきたい場合は、依存オブジェクトをインスタンス化するメソッドを使う際に「permanent: true」と宣言してください)これにより時間が節約できますし、不要な依存オブジェクトがメモリ上に残るリスクも少なくなります。メモリへの読み込みについてもデフォルトは遅延読み込みであり、使用するときに初めてメモリ上に読み込まれます。
- **コードの分離性:** GetXを使うと、ビュー、プレゼンテーションロジック、ビジネスロジック、依存オブジェクトの注入、およびナビゲーション周りのコードを書き分けやすくなります。Routeのナビゲーションにはcontextを必要としないため、Widgetツリーに依存することはありません。ロジックについてもInheritedWidget経由でController/BLoCにアクセスする際のcontextは必要ありません。プレゼンテーションロジックとビジネスロジックをUIクラスから完全に切り離すことができます。また、Controller/モデル/BLoCのクラスを、`MultiProvider`を使ってWidgetツリーに注入する必要もありません。GetXでは独自の依存オブジェクト注入機能を使用し、ビュークラスからビューとは無関係なコードをなくすことができるのです。
GetXを使うことでアプリケーションの各機能がどこにあるのかがわかりやすくなり、自然と見やすいコードになります。メンテナンスが容易になるだけでなく、それまでのFlutterでは考えられなかったモジュール共有が簡単に実現できるようになりました。
BLoCはこの分野におけるFlutterの出発点と言えるものでしたが、GetXはこれを正統進化させており、ビジネスロジックのみならずプレゼンテーションロジックも分離することができます。そのほかデータレイヤーはもちろん、依存オブジェクトやRouteの注入に関するコードも。どこに何が配置されているのか全体の見通しがしやすくなり、Hello Worldを表示させるかのように簡単にアプリの機能を利用できるようになるでしょう。
Flutterアプリを作るならGetXは最も簡単で実用的、かつスケーラブルなソリューションです。強力なエコシステムも存在があるため、初心者にはわかりやすさ、プロには正確性を提供することができます。そしてFlutter SDKにはない幅広い種類のAPIを提供し、セキュアで安定的な環境を構築します。
- GetXは肥大化したライブラリではありません。何も気にせずすぐに開発を始められるよう多数の機能を標準で備えていますが、それぞれの機能は個別にコンテナに入っており、使用してはじめて起動します。状態管理機能しか利用していない場合はその機能だけがコンパイルされます。Route管理機能だけを利用していれば、状態管理機能がコンパイルされることはありません。
- GetXには巨大なエコシステム、コミュニティ、コラボレーターの存在があるため、Flutterが存在する限りメンテナンスされ続けます。またGetXもFlutterと同様にAndroid、iOS、Web、Mac、Linux、Windows、そしてあなたのサーバー上で、単一のコードから実行することができます。
**[Get Server](https://github.com/jonataslaw/get_server)を使うことで、フロントエンドで作成したコードをバックエンドで再利用することが可能です。**
**さらに、[Get CLI](https://github.com/jonataslaw/get_cli)を使えば、サーバー側でもフロントエンド側でも開発プロセス全体を自動化することができます。**
**また、生産性をさらに高めるためのツールとして、[VSCode用の拡張機能](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) と [Android Studio/Intellij用の拡張機能](https://plugins.jetbrains.com/plugin/14975-getx-snippets)があります。**
# インストール方法
Getパッケージを pubspec.yaml に追加します:
```yaml
dependencies:
get:
```
使用するときはこのようにインポートしてください:
```dart
import 'package:get/get.dart';
```
# GetXによるカウンターアプリ
Flutterで新規プロジェクトを作成する際に表示されるカウンターアプリは、コメントを含めると100行以上あります。Getの実力を示すため、このカウンターアプリを可読性を重視した形で、コメントを含めてわずか26行のコードで作成する方法を紹介します。
- ステップ1:
MaterialAppの前に「Get」を足して、GetMaterialAppにします。
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
- 注1: GetMaterialAppはFlutterのMaterialAppに手を加えたものではありません。MaterialAppをchildに持ち、諸々の追加設定をしてくれるWidgetに過ぎません。この設定は手動でも可能ですが、その必要はありません。GetMaterialAppは、Routeの作成・注入、言語翻訳の注入など、ナビゲーションに必要なものをすべて注入してくれます。Getを状態管理や依存オブジェクト管理に限定して使用する場合は、GetMaterialAppを使用する必要はありません。GetMaterialAppは、Route、SnackBar、多言語対応、BottomSheet、Dialog、contextなしの高レベルAPIを利用する場合に必要です。
- 注2: このステップは、Route管理機能(`Get.to()`や`Get.back()`など)を使用しない場合は、必要ありません。
- ステップ2:
ビジネスロジッククラスを作成し、そこに必要な変数、メソッド、コントローラをすべて配置します。
変数に ".obs" を付け足すことで、その変数の値の変化を監視することが可能になります。
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
- ステップ3:
ビューを作成します。StatelessWidgetを使用することでRAMが節約できます。GetではStatefulWidgetを使用する必要がなくなるかもしれません。
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Get.put()を使ってクラスをインスタンス化することですべての子Routeで利用できるようになります。
final Controller c = Get.put(Controller());
return Scaffold(
// countが変わるたびにTextを更新するにはObx(()=>)を使ってください。
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// 8行使っていたNavigator.pushの代わりに短い Get.to()を使ってください。context不要です。
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// 他のページで使われているコントローラーを見つけてきてくれます。
final Controller c = Get.find();
@override
Widget build(context){
// 最新のcount変数の値にアクセス
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
Result:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
これはシンプルな例ですが、すでにGetがいかに強力であるかがわかると思います。プロジェクトが大きければ大きいほど、この差はもっと開くでしょう。
Getはチームでの作業を想定して設計されていますが、個人開発者の仕事もシンプルにしてくれます。
パフォーマンスを落とさず納期までにすべて納品。Getはすべての人に向いているわけではありませんが、このフレーズにぴんと来た人には確実に向いています!
# 三本柱
## 状態管理
Getの状態管理には、非リアクティブ(GetBuilder)と、リアクティブ(GetX/Obx)の2つのアプローチがあります。
### リアクティブな状態管理
リアクティブプログラミングは複雑であると言われ、多くの人に敬遠されています。GetXは、リアクティブプログラミングをシンプルなものに変えます:
* StreamControllerを作る必要はありません。
* 変数ごとにStreamBuilderをセットする必要はありません。
* 状態ごとにクラスを作る必要はありません。
* 初期値のためにgetを準備する必要はありません。
- コードの自動生成をする必要がありません。
GetにおけるリアクティブプログラミングはsetStateと同じように簡単です。
例えば、名前の変数があって、それを変更するたびに、その名前を使っているすべてのWidgetを自動で更新したい場合。
```dart
var name = 'Jonatas Borges';
```
このnameをObservable(監視可能)にするには, ".obs"を値の末尾に付けるだけです。
```dart
var name = 'Jonatas Borges'.obs;
```
UIでその値を表示し、値が変わるたびに内容を更新したい場合は次のようにします。
```dart
Obx(() => Text("${controller.name}"));
```
以上です。こんなに簡単なんですよ。
### 状態管理に関する詳細ドキュメント
**状態管理に関するより詳細な説明を知りたい方は[こちらの日本語ドキュメント](./documentation/ja_JP/state_management.md)をご覧ください。多くの事例や、非リアクティブな状態管理とリアクティブな状態管理の違いについても説明されています。**
GetXパワーがもたらす利点をより理解していただけると思います。
## Route管理
GetXはcontextなしでRoute/SnackBar/Dialog/BottomSheetを使用することができます。具体的に見ていきましょう。
いつものMaterialAppの前に「Get」を付け足して、GetMaterialAppにしましょう。
```dart
GetMaterialApp( // MaterialApp の前に Get
home: MyHome(),
)
```
新しいRouteに画面遷移するにはこのシンタックス。
```dart
Get.to(NextScreen());
```
名前付きRouteに画面遷移するにはこのシンタックス。名前付きRouteの詳細は[こちらの日本語ドキュメント](./documentation/ja_JP/route_management.md#navigation-with-named-routes)
```dart
Get.toNamed('/details');
```
SnackBar、Dialog、BottomSheetなど、Navigator.pop(context)で閉じられるRouteはこれで閉じます。
```dart
Get.back();
```
次の画面に移動した後、前の画面に戻れないようにする場合(スプラッシュスクリーンやログイン画面など)はこちら。
```dart
Get.off(NextScreen());
```
次の画面に進み、前のRouteをすべてキャンセルする場合(ショッピングカート、アンケート、テストなど)はこちら。
```dart
Get.offAll(NextScreen());
```
以上、contextを一度も使わなかったことに気付きましたか?これがGetでRoute管理を行う最大のメリットのひとつです。contextを使わないので、たとえばcontrollerクラスの中でも、これらのメソッドを実行することができます。
### Route管理に関する詳細ドキュメント
**Getは名前付きRouteでも動作し、Routeの下位レベルの制御も可能です。詳細なドキュメントは[こちらの日本語ドキュメント](./documentation/ja_JP/route_management.md)にあります。**
## 依存オブジェクト管理
Getにはシンプルで強力な依存オブジェクト注入機能があります。わずか1行のコードで、Provider contextやinheritedWidgetも使わず、BLoCやControllerのようなクラスのインスタンスを取得することができます。
```dart
Controller controller = Get.put(Controller()); // controller = Controller() とする代わりに
```
- 注: Getの状態管理機能を使用している場合は、Bindings APIにもご注目を。BindingsはビューとControllerを結びつけるのをより便利にしてくれます。
一つのクラスの中でControllerクラスをインスタンス化するのではなく、Getインスタンスの中でインスタンス化することで、アプリ全体でControllerが利用できるようになります。
**ヒント:** Getの依存オブジェクト注入機能の部分は、パッケージ全体の中でも他の部分と切り離されているので、たとえば、あなたのアプリがすでに状態管理機能を一部で使用していたとしても、それらを書き直す必要はなく、この依存オブジェクト注入機能をそのまま使用することができます。
```dart
controller.fetchApi();
```
色々なRouteを行き来した後に、あるControllerクラスのデータにアクセスする必要が生じたとしましょう。ProviderやGet_itなら再びそのクラスに依存オブジェクトを注入する必要がありますよね?Getの場合は違います。Getでは「find」と依頼するだけで、追加の依存オブジェクトの注入は必要ありません。
```dart
Controller controller = Get.find();
//マジックみたいですね。Getは正しいcontrollerをきちんと探してきてくれますよ。100万のcontrollerのインスタンスがあっても、Getは必ず正しいcontrollerを探し当てます。
```
そして、findで取得したコントローラーのデータをこのように呼び出すことができます。
```dart
Text(controller.textFromApi);
```
### 依存オブジェクト管理に関する詳細ドキュメント
**依存オブジェクト管理に関するより詳細な説明は[こちらの日本語ドキュメント](./documentation/ja_JP/dependency_management.md)をご覧ください。**
# ユーティリティ
## 多言語対応
### 翻訳ファイル
翻訳ファイルはシンプルなキーと値のMapとして保持されます。
翻訳を追加するには、クラスを作成して `Translations` を継承します。
```dart
import 'package:get/get.dart';
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello World',
},
'de_DE': {
'hello': 'Hallo Welt',
}
};
}
```
#### 翻訳ファイルの利用
指定されたキーに `.tr` (translateのtr)を追加するだけで、`Get.locale` と `Get.fallbackLocale` の現在の値をに沿って適切な言語に翻訳されます。
```dart
Text('title'.tr);
```
#### 単数系と複数形に対応
```dart
var products = [];
Text('singularKey'.trPlural('pluralKey', products.length, Args));
```
#### パラメーターに対応
```dart
import 'package:get/get.dart';
Map<String, Map<String, String>> get keys => {
'en_US': {
'logged_in': 'logged in as @name with email @email',
},
'es_ES': {
'logged_in': 'iniciado sesión como @name con e-mail @email',
}
};
Text('logged_in'.trParams({
'name': 'Jhon',
'email': 'jhon@example.com'
}));
```
### ロケール
ロケールと翻訳を定義するため、`GetMaterialApp`にパラメータを渡します。
```dart
return GetMaterialApp(
translations: Messages(), // Translationsを継承したクラスのインスタンス
locale: Locale('en', 'US'), // このロケール設定に沿って翻訳が表示される
fallbackLocale: Locale('en', 'UK'), // 無効なロケールだったときのフォールバックを指定
);
```
#### ロケールの変更
ロケールを変更するには、`Get.updateLocale(locale)`を呼び出します。翻訳は新しいロケールに沿ってなされます。
```dart
var locale = Locale('en', 'US');
Get.updateLocale(locale);
```
#### システムのロケールを読み込む
システムのロケールを読み込むには、`Get.deviceLocale`を使用します。
```dart
return GetMaterialApp(
locale: Get.deviceLocale,
);
```
## Themeの変更
`GetMaterialApp`より上位のWidgetを使ってThemeを変更しないでください。Keyの重複を引き起こす可能性があります。アプリのThemeを変更するためには「ThemeProvider」Widgetを作成するという前時代的なアプローチが採られることが多いですが、**GetX™**ではこのようなことは必要ありません。
カスタムのThemeDataを作成したら、それを`Get.changeTheme`内に追加するだけです。
```dart
Get.changeTheme(ThemeData.light());
```
もし、`onTap`でThemeを変更するボタンを作りたいのであれば、以下の2つの**GetX™** APIを組み合わせることができます。
- Dark Theme が使われているかどうかをチェックするAPI
- Theme を変えるAPI(ボタンの`onPressed`の中に設置できます)
```dart
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
```
Darkモードが有効であれば、_light theme_に切り替わり、Lightモードが有効なら、_dark theme_に切り替わります。
## GetConnect
GetConnect は、http または websocket を使用してバックエンドとフロントエンド間の通信を行う機能です。
### デフォルト設定
GetConnectを拡張することで、GET/POST/PUT/DELETE/SOCKETメソッドを使用して、Rest APIやウェブソケットと通信することができます。
```dart
class UserProvider extends GetConnect {
// Get リクエスト
Future<Response> getUser(int id) => get('http://youapi/users/$id');
// Post リクエスト
Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
// File付き Post リクエスト
Future<Response<CasesModel>> postCases(List<int> image) {
final form = FormData({
'file': MultipartFile(image, filename: 'avatar.png'),
'otherFile': MultipartFile(image, filename: 'cover.png'),
});
return post('http://youapi/users/upload', form);
}
GetSocket userMessages() {
return socket('https://yourapi/users/socket');
}
}
```
### カスタム設定
GetConnect は高度なカスタマイズが可能です。ベースUrlの定義はもちろん、リクエストヘッダーを足したり、レスポンスボディに変更を加えたり、認証情報を追加したり、認証回数の制限を設けたりすることができるほか、リクエストをModelに変換するデコーダを定義することもできます。
```dart
class HomeProvider extends GetConnect {
@override
void onInit() {
// デフォルトデコーダーをセット
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.baseUrl = 'https://api.covid19api.com';
// baseUrlをセット
// リクエストヘッダーに 'apikey' プロパティを付け足しています。
httpClient.addRequestModifier((request) {
request.headers['apikey'] = '12345678';
return request;
});
// サーバーが"Brazil"を含むデータを送ってきてもユーザーに表示されることはありません。
// レスポンスがUIレイヤーに届けられる前にデータが取り除かれているからです。
httpClient.addResponseModifier<CasesModel>((request, response) {
CasesModel model = response.body;
if (model.countries.contains('Brazil')) {
model.countries.remove('Brazilll');
}
});
httpClient.addAuthenticator((request) async {
final response = await get("http://yourapi/token");
final token = response.body['token'];
// ヘッダーをセット
request.headers['Authorization'] = "$token";
return request;
});
// HttpStatus が HttpStatus.unauthorized である限り、
// 3回まで認証が試みられます。
httpClient.maxAuthRetries = 3;
}
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
}
```
## GetPageにミドルウェアを設定
GetPageに新しいプロパティが追加され、GetMiddleWareのListを設定することができるようになりました。GetMiddleWareは設定した任意の順序で実行されます。
**注**: GetPageにミドルウェアを設定すると、そのページの子ページはすべて同じミドルウェアを自動的に持つことになります。
### 実行優先度
GetMiddlewareに設定したpriority(優先度)の若い順にミドルウェアが実行されます。
```dart
final middlewares = [
GetMiddleware(priority: 2),
GetMiddleware(priority: 5),
GetMiddleware(priority: 4),
GetMiddleware(priority: -8),
];
```
この場合の実行順序は **-8 => 2 => 4 => 5**
### redirect
redirect関数は、Routeを呼び出してページが検索されると実行されます。リダイレクト先のRouteSettingsが戻り値となります。もしくはnullを与えれば、リダイレクトは行われません。
```dart
RouteSettings redirect(String route) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login')
}
```
### onPageCalled
onPageCalled関数は、ページが呼び出された直後に実行されます。
この関数を使ってページの内容を変更したり、新しいページを作成したりすることができます。
```dart
GetPage onPageCalled(GetPage page) {
final authService = Get.find<AuthService>();
return page.copyWith(title: 'Welcome ${authService.UserName}');
}
```
### onBindingsStart
onBindingsStart関数は、Bindingsが初期化される直前に実行されます。
たとえば、ページのBindingsを変更することもできます。
```dart
List<Bindings> onBindingsStart(List<Bindings> bindings) {
final authService = Get.find<AuthService>();
if (authService.isAdmin) {
bindings.add(AdminBinding());
}
return bindings;
}
```
### onPageBuildStart
onPageBuildStart関数は、Bindingsが初期化された直後、ページWidgetが作成される前に実行されます。
```dart
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
print('bindings are ready');
return page;
}
```
### onPageBuilt
onPageBuilt関数は、GetPage.page(ページのビルダー)が呼び出された直後に実行され、表示されるWidgetを結果として受け取ることができます。
### onPageDispose
onPageDispose関数は、ページに関するすべてのオブジェクト(Controller、ビューなど)が破棄された直後に実行されます。
## その他API
```dart
// 現在の画面に渡されているargs(引数)を取得
Get.arguments
// 直前のRouteの名前("/" など)を取得
Get.previousRoute
// 現在のRouteオブジェクトを取得
Get.rawRoute
// GetObserverからRoutingを取得
Get.routing
// SnackBarが開いているかチェック
Get.isSnackbarOpen
// Dialogが開いているかチェック
Get.isDialogOpen
// BottomSheetが開いているかチェック
Get.isBottomSheetOpen
// Routeを削除
Get.removeRoute()
// 引数のRoutePredicateがtrueを返すまで画面を戻る
Get.until()
// 引数で指定したRouteに進み、RoutePredicateがtrueを返すまで画面を戻る
Get.offUntil()
// 引数で指定した名前付きRouteに進み、RoutePredicateがtrueを返すまで画面を戻る
Get.offNamedUntil()
// アプリがどのプラットフォームで実行されているかのチェック
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
// アプリがどのデバイスで実行されているかのチェック
GetPlatform.isMobile
GetPlatform.isDesktop
// プラットフォームとデバイスのチェックは独立
// 同じOSでもウェブで実行されているのか、ネイティブで実行されているのか区別
GetPlatform.isWeb
// MediaQuery.of(context).size.height と同じ
// ただしimmutable
Get.height
Get.width
// Navigatorの現在のcontextを取得
Get.context
// SnackBar/Dialog/BottomSheet などフォアグラウンドのcontextを取得
Get.overlayContext
// 注: 以降のメソッドはcontextの拡張メソッドです。
// contextと同じくUIのどこからでもアクセスできます。
// ウィンドウサイズの変更などに合わせて変わる height/width を取得
context.width
context.height
// 画面の半分のサイズ,1/3のサイズなどを取得
// レスポンシブなデザインの場合に便利
// オプションのパラメーター dividedBy で割る数を指定
// オプションのパラメーター reducedBy でパーセンテージを指定
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より大きい場合にtrueを返す
context.showNavbar()
/// 画面の短辺が600より小さい場合にtrueを返す
context.isPhone()
/// 画面の短辺が600より小さい場合にtrueを返す
context.isSmallTablet()
/// 画面の短辺が720より大きい場合にtrueを返す
context.isLargeTablet()
/// デバイスがタブレットの場合にtrueを返す
context.isTablet()
/// 画面サイズに合わせて value<T> を返す
/// たとえば:
/// 短辺が300より小さい → watchパラメーターの値を返す
/// 短辺が600より小さい → mobileパラメーターの値を返す
/// 短辺が1200より小さい → tabletパラメーターの値を返す
/// 横幅が1200より大きい → desktopパラメーターの値を返す
context.responsiveValue<T>()
```
### オプションのグローバル設定と手動設定
GetMaterialApp はすべてあなたの代わりに設定してくれますが、手動で設定を施したい場合は MaterialApp の navigatorKey と navigatorObservers の値を指定してください。
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
```
`GetObserver`内で独自のミドルウェアを使用することもできます。これは他に影響を及ぼすことはありません。
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // ここ
],
);
```
`Get` クラスに_グローバル設定_を施すことができます。Routeをプッシュする前のコードに `Get.config` を追加するだけです。もしくは、`GetMaterialApp` 内で直接設定することもできます。
```dart
GetMaterialApp(
enableLog: true,
defaultTransition: Transition.fade,
opaqueRoute: Get.isOpaqueRouteDefault,
popGesture: Get.isPopGestureEnable,
transitionDuration: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino
)
```
オプションで、すべてのログメッセージを `Get` からリダイレクトさせることができます。
お好みのロギングパッケージを使ってログを取得したい場合はこのようにしてください。
```dart
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// ここでお好みのロギングパッケージにメッセージを渡してください
// enableLog: false にしても、ログメッセージはこのコールバックでプッシュされる点ご注意を
// ログが有効かどうかのチェックは Get.isLogEnable で可能
}
```
### ローカルステートWidget
ローカルステートWidgetは、1つの変数の状態を一時的かつローカルに管理したい場合に便利です。
シンプルなValueBuilderとリアクティブなObxValueの2種類があります。
たとえば、`TextField` Widgetの obscureText プロパティを切り替えたり、折りたたみ可能なパネルをカスタムで作成したり、`BottomNavigation` の現在のインデックス値を変更して内容を変更したりといった用途に最適です。
#### ValueBuilder
setStateでお馴染みの `StatefulWidget` をシンプルにしたビルダーWidgetです。
```dart
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // ( newValue ) => updateFn( newValue ) も可
),
// builderメソッドの外で何か実行する場合
onUpdate: (value) => print("Value updated: $value"),
onDispose: () => print("Widget unmounted"),
),
```
#### ObxValue
[`ValueBuilder`](#valuebuilder)に似ていますが、これはそのリアクティブバージョンです。Rxインスタンス(.obsを付けたときに戻る値です)を渡すと自動で更新されます。すごいでしょ?
```dart
ObxValue((data) => Switch(
value: data.value,
onChanged: data,
// Rxには_呼び出し可能な_関数が備わっているのでこれだけでOK
// (flag) => data.value = flag も可能
),
false.obs,
),
```
## お役立ちTIPS
`.obs`が付いた型(_Rx_型とも呼ばれる)には、さまざまな内部メソッドや演算子が用意されています。
> `.obs`が付いたプロパティが **実際の値** だと信じてしまいがちですが...間違えないように!
> 我々がcontrollerにおける変数の型宣言を省略してvarとしているのはDartのコンパイラが賢い上に、
> そのほうがコードがすっきる見えるからですが…
```dart
var message = 'Hello world'.obs;
print( 'Message "$message" has Type ${message.runtimeType}');
```
`message`を _print_ することで実際の文字列が取り出されはしますが、型は **RxString** です!
そのため `message.substring( 0, 4 )` などといったことはできません。
Stringのメソッドにアクセスするには _observable_ の中にある実際の値 `value` にアクセスします。
アクセスには `.value`を使うのが通常ですが、他の方法もあるのでご紹介します。
```dart
final name = 'GetX'.obs;
// 新しい値が現在のものと異なる場合のみ Stream が更新されます。
name.value = 'Hey';
// すべてのRxプロパティは「呼び出し可能」で、valueを返してくれます。
// ただし `null` は受付不可。nullの場合はUIが更新されない。
name('Hello');
// これはgetterみたいなものです。'Hello' を返します。
name() ;
/// num型の場合
final count = 0.obs;
// num型の非破壊的な演算子はすべて使えます。
count + 1;
// 注意! この場合は`count`がfinalなら有効ではないです。varなら有効。
count += 1;
// 比較演算子も使用可能
count > 2;
/// bool型の場合
final flag = false.obs;
// true/false を入れ替えることができます。
flag.toggle();
/// すべての型
// `value` を null にセット。
flag.nil();
// toString(), toJson() などの操作はすべて `value` が対象になります。
print( count ); // RxIntの `toString()` が呼び出されて数字がprintされる。
final abc = [0,1,2].obs;
// json配列に変換した値と、'RxList' がprintされます。
// JsonはすべてのRx型でサポートされています!
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap、RxList、RxSetはそれぞれの元の型を拡張した特別なRx型です。
// たとえばRxListは通常のListとして扱うことができる上にリアクティブです。
abc.add(12); // 12をListにプッシュし、Streamを更新してくれます。
abc[3]; // Listと同様にインデックス番号3の値を取得してくれます。
// 等価演算子はRx型と元の型でも動作しますが、.hashCode は常にvalueから取得します。
final number = 12.obs;
print( number == 12 ); // true
/// カスタムのRxモデル
// toJson()やtoString()をモデルクラスに設定すれば、.obsからでもprintされるように実装可能。
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age years old';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
// `user` 自体はリアクティブですが、その中のプロパティはリアクティブではありません。
// そのため、このようにプロパティの値を変更してもWidgetは更新されません。
user.value.name = 'Roi';
// `Rx` には自ら変更を検知する手段がないからです。
// そのため、カスタムクラスの場合はこのようにWidgetに変更を知らせる必要があります。
user.refresh();
// もしくは `update()` メソッドを使用してください。
user.update((value){
value.name='Roi';
});
print( user );
```
#### StateMixin
`UI`の状態を管理するもう一つの手法として、`StateMixin<T>`を利用する方法があります。
controllerクラスに`with`を使って`StateMixin<T>`を追加することで実装可能です。
``` dart
class Controller extends GetController with StateMixin<User>{}
```
`change()`メソッドにより好きなタイミングで状態を変更することができます。
このようにデータと状態を渡すだけです。
```dart
change(data, status: RxStatus.success());
```
RxStatus には以下のステータスが存在します。
``` dart
RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');
```
ステータスごとにUIを設定するにはこのようにします。
```dart
class OtherClass extends GetView<Controller> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.obx(
(state)=>Text(state.name),
// ローディング中はカスタムのインジケーターの設定も可能ですが、
// デフォルトで Center(child:CircularProgressIndicator()) となります。
onLoading: CustomLoadingIndicator(),
onEmpty: Text('No data found'),
// 同様にエラーWidgetはカスタム可能ですが、
// デフォルトは Center(child:Text(error)) です。
onError: (error)=>Text(error),
),
);
}
```
#### GetView
このWidgetは私のお気に入りです。とてもシンプルで扱いやすいですよ!
このWidgetを一言で表現すると、「controllerをgetterに持つ `const` な StatelessWidget」です。
```dart
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
// controllerの `型` を渡すのを忘れずに!
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // `controller.なんとか` でアクセス
);
}
}
```
#### GetResponsiveView
GetViewをレスポンシブデザインに対応させたい場合はこのWidgetを継承してください。
画面サイズやデバイスタイプなどの情報を持つ `screen` プロパティを保持しています。
##### 使い方
Widgetをビルドする方法は2つあります。
- `builder` メソッドを使う。
- `desktop`, `tablet`, `phone`, `watch` メソッドを使う。
画面サイズ、デバイスタイプに応じたWidgetがビルドされます。
たとえば画面が [ScreenType.Tablet] なら `tablet` メソッドが実行されます。
**注:** `alwaysUseBuilder` プロパティをfalseにする必要があります。
`settings` プロパティでブレイクポイントを設定することもできます。
![](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
この画面のコード
[コード](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
#### GetWidget
このWidgetはあまり知られておらず、使用するケースは稀です。
GetViewとの違いは、Controllerを`キャッシュ`してくれる点です。
このキャッシュがあるため `const` にはできません。
> それでは一体いつControllerをキャッシュする必要があるのかって?
それは **GetX** のこれまた使う機会の少ない `Get.create()` を使うときです。
`Get.create(()=>Controller())` は `Get.find<Controller>()` を実行するたびに
新しいControllerインスタンスを生成します。
そこで `GetWidget` の出番です。たとえば、Todoアイテムのリスト内容を保持したいとき。
Widgetが更新されてもアイテムはControllerのキャッシュを参照してくれます。
#### GetxService
このクラスは `GetxController` に似ており、同様のライフサイクル(`onInit()`, `onReady()`, `onClose()`)を共有しますが、そこに「ロジック」はありません。**GetX**の依存オブジェクト注入システムに、このサブクラスがメモリから **削除できない** ということを知らせるだけです。
そのため `Get.find()` で `ApiService`, `StorageService`, `CacheService` のようなサービス系クラスにいつでもアクセスできるようにしておくと非常に便利です。
```dart
Future<void> main() async {
await initServices(); /// サービスクラスの初期化をawait
runApp(SomeApp());
}
/// Flutterアプリ実行前にサービスクラスを初期化してフローをコントロールするのは賢いやり方です。
/// たとえば GetMaterialAppを更新する必要がないようにUser別の
/// Theme、apiKey、言語設定などをApiサービス実行前にロードしたり。
void initServices() async {
print('starting services ...');
/// get_storage, hive, shared_pref の初期化はここで行います。
/// あるいは moor の connection など非同期のメソッドならなんでも。
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
```
`GetxService` を破棄する唯一の方法は `Get.reset()` メソッドを使うことです。
これはアプリにおける「ホットリブート」のようなものです。あるクラスのインスタンスを
ライフサイクルの間ずっと残しておきたい場合は `GetxService` を使うというのを覚えておいてください。
## テストの実行
Controllerのライフサイクル含め、他のクラスと同様にテストを実行することができます。
```dart
class Controller extends GetxController {
@override
void onInit() {
super.onInit();
// 値を name2 に変更
name.value = 'name2';
}
@override
void onClose() {
name.value = '';
super.onClose();
}
final name = 'name1'.obs;
void changeName() => name.value = 'name3';
}
void main() {
test('''
Test the state of the reactive variable "name" across all of its lifecycles''',
() {
/// ライフサイクルごとのテストは必ずしも行う必要はありませんが、
/// GetXの依存オブジェクト注入機能を使用しているのであれば実行をおすすめします。
final controller = Controller();
expect(controller.name.value, 'name1');
/// このようにライフサイクル経過ごとの状態をテスト可能です。
Get.put(controller); // onInit が実行される
expect(controller.name.value, 'name2');
/// 関数もテストしましょう
controller.changeName();
expect(controller.name.value, 'name3');
/// onClose が実行される
Get.delete<Controller>();
expect(controller.name.value, '');
});
}
```
#### mockitoやmocktailを使う場合
GetxController/GetxService をモックする場合 Mock をミックスインしてください。
```dart
class NotificationServiceMock extends GetxService with Mock implements NotificationService {}
```
#### Get.reset()
WidgetやGroupのテスト時に、テストの最後かtearDownの中で Get.reset() を実行することで設定をリセットすることができます。
#### Get.testMode
Controllerの中でナビゲーションを使用している場合は、`Get.testMode = true`をmainの開始で実行してください。
# バージョン2.0からの破壊的変更
1- Rx型の名称
| 変更前 | 変更後 |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RxControllerとGetBuilderが統合され、Controllerにどれを使うか覚えておく必要がなくなりました。GetxControllerを使うだけで、リアクティブと非リアクティブな状態管理の両方に対応できるようになりました。
2- 名前付きRoute
変更前:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
変更後:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
```
変更の効果:
ページ表示にはパラメータやログイントークンを起点にする方法もありますが、以前のアプローチではこれができず、柔軟性に欠けていました。
ページを関数から取得するよう変更したことで、このようなアプローチを可能にし、アプリ起動直後にRouteがメモリに割り当てられることもないため、RAMの消費量を大幅に削減することもできました。
```dart
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
# なぜGetXなのか
1- Flutterのアップデートが重なると、依存パッケージがうまく動かなくなることがあります。コンパイルエラーを起こしたり、その時点で解決方法がないようなエラーが発生したり。開発者はそのエラーを追跡し、該当リポジトリにissueを提起し、問題が解決されるのを待つ必要があります。Getは開発に必要な主要リソース(状態管理、依存オブジェクト管理、Route管理)を一元化し、Pubspecにパッケージを1つ追加するだけでコーディングを開始することができます。Flutterがアップデートしたときに必要なことは、Getも併せてアップデートすることだけです。それですぐに作業を再開できます。またGetはパッケージ間の互換性の問題も解消します。互いに依存するパッケージAの最新バージョンとBの最新バージョンの間に互換性がない、ということが何度あったでしょうか。Getを使えばすべてが同じパッケージ内にあるため、互換性の心配はありません。
2- Flutterは手軽で素晴らしいフレームワークですが、`Navigator.of(context).push (context, builder [...]`のように、ほとんどの開発者にとって不要な定型文が一部にあります。Getを使えばそのような定型文を簡素化できます。Routeを呼ぶためだけに8行のコードを書く代わりに、`Get.to(Home())`を実行すれば、次の画面に遷移することができるのです。またウェブURLを動的なものにすることは現在Flutterでは本当に骨の折れる作業ですが、GetXを使えば非常に簡単です。そしてFlutterにおける状態管理と依存オブジェクト管理については、たくさんのパターンやパッケージがあるので多くの議論を生んでいます。しかしGetXのアプローチは大変シンプルです。これは一例ですが、変数の最後に「.obs」を追加して「Obx()」の中にWidgetを配置するだけで、その変数の状態変化が自動でWidgetに反映されます。
3- GetXではパフォーマンスのことをあまり気にせず開発ができます。Flutterのパフォーマンスはそれだけで素晴らしいものですが、状態管理と併せて BLoC / データストア / Controller などを届けるためのサービスロケーターを使用することを想像してみてください。そのインスタンスが必要ないときはリソースを解放するイベントを明示的に呼び出さなければなりません。そんなとき、使用されなくなったら自動でメモリから削除してくれればいいのに、と考えたことはありませんか?それを実現してくれるのがGetXです。SmartManagement機能により未使用のリソースはすべて自動でメモリから破棄されるので、本来の開発作業に集中することができます。メモリ管理のためのロジックを作らなくても、常に必要最小限のリソースを使っていることが保証されるのです。
4- コードのデカップリング(分離)がしやすい。「ビューをビジネスロジックから分離する」というコンセプトを聞いたことがあるかもしれません。これはなにもBLoC、MVC、MVVMに限ったことではなく、どのアーキテクチャパターンもこのコンセプトが考え方の基本にあると言っていいでしょう。しかし、Flutterではcontextの使用によりこのコンセプトが薄まってしまいがちです。
InheritedWidgetを参照するためにcontextが必要なとき、ビューの中でそれを使用するか、引数としてcontextを渡しますよね?私はこの方法は美しくないと感じます。常にビュー内のビジネスロジックに依存しなければならないのは、特にチームで仕事をする場面においては不便だと感じます。GetXによるアプローチでは、StatefulWidgetやinitStateなどの使用を禁止しているわけではありませんが、それらよりもずっとスッキリ書けるようになっています。Controller自体にライフサイクルがあるため、たとえばREST APIのリクエストを行うときも、ビューの中の何かに依存するということがありません。Controllerのライフサイクルの一つである onInit を使用してhttpを呼び出し、データが到着すると変数にセットされます。GetXはリアクティブな変数を扱うことができるので、インスタンス変数が変わりし次第、その変数に依存するWidgetがすべて自動更新されます。これによりUIの担当者はWidgetの見た目に注力することができ、ボタンクリックなどのユーザーイベント以外のものをビジネスロジックに渡す必要がなくなります。その一方でビジネスロジックの担当者はビジネスロジックだけに集中し、個別のテストを簡単に行うことができます。
GetXライブラリは今後も更新され続け、新しい機能を実装していきます。気軽にプルリクエストを出していただき、ライブラリの成長に貢献していただけるとうれしいです。
# コミュニティ
## コミュニティチャンネル
GetXコミュニティは非常に活発で有益な情報であふれています。ご質問がある場合や、このフレームワークの使用に関して支援が必要な場合は、ぜひコミュニティチャンネルにご参加ください。このリポジトリは、issueの提起およびリクエスト専用ですが、気軽にコミュニティにご参加いただければ幸いです。
| **Slack** | **Discord** | **Telegram** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) |
## コントリビュート方法
_GetXプロジェクトに貢献してみませんか?あなたをコントリビューターの一人としてご紹介できるのを楽しみにしています。GetおよびFlutterをより良いものにするためのコントリビュート例をご紹介します。_
- Readmeの多言語対応。
- Readmeの追加ドキュメント執筆 (ドキュメントで触れられていない機能がまだまだたくさんあります)。
- Getの使い方を紹介する記事やビデオの作成(Readmeに掲載させていただきます。将来的にWikiができればそこにも掲載予定)。
- コードやテストのプルリクエスト。
- 新機能の提案。
どのような形の貢献であれ歓迎しますので、ぜひコミュニティにご参加ください!
## GetXに関する記事と動画
- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).
- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.
- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.
- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.
- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.
- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.
- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman).
- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman).
- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli.
- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli.
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
... ...