Natesh Bhat
Committed by GitHub

Merge branch 'master' into master

Too many changes to show.

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

No preview for this file type
... ... @@ -23,7 +23,7 @@ jobs:
# https://github.com/marketplace/actions/flutter-action
- uses: subosito/flutter-action@v1
with:
flutter-version: "1.22.3"
flutter-version: "2.0.2"
channel: "stable"
- run: flutter pub get
#- run: flutter analyze
... ...
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 60bd88df915880d23877bfc1602e8ddcf4c4dd2a
channel: stable
project_type: app
... ...
## [3.25.0]
## [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
## [4.0.2]
- Removed "!" of if else conditions until the null-safety of the dart is consistent for using it.
## [4.0.1]
- Fix changelog
## [4.0.0]
- Added append function to StateMixin. Now is possible track loading, success and error handle of your application with ONE LINE OF CODE. Ex: append(()=> api.getUser);
- Migrate to null-safety
- Added ScrollMixin to controllers
- Added loadingMore status to RxStatus
- Fix content-type qual null (@katekko)
- Made GetInstance non nullable (@eduardoflorence)
- Fix multi-parameters url (@iMrLopez)
- Fix Expected value of SkDeletable error (@obadajasm)
- Added triggers, an Rx method that triggers events, even if they are the same as the previous event (@RafaRuiz)
- Improve docs: (@CNAD666), (@dhhAndroid), (@Jackylee1992),
Switching to null-safety:
You can continue using GetX as normal, with as little breaking changes as possible.
It is still possible to declare the var.obs variable, and this remains the preferred way, forcing null-safety and giving you all the security that sound null-safety delivers to your app. However, if you need to use null, we also provide a solution for you.
Declare the variables with `?` Ex: `final Rx<int?> count = 0.obs`.
You can also use custom Rxn types with null-safety:
`RxInt` == not nullable
`RxnInt` == nullable.
## [3.25.6]
- Added documentation in French (@kamazoun)
- Fix logs messages (@damphat)
- Fix plural to zero on internacionalization (@RafaRuiz)
- Fix error when body hasn't content on GetConnect (@jasonlaw)
- Fix typos on readme (@bashleigh)
- Fix group updates to GetBuilder
## [3.25.5]
- Fix Get.isDialogOpen when two or more open dialogs are closed
## [3.25.4]
- Added logs and tests to unknownRoute
## [3.25.3]
- Fix bindStream error 'Object.noSuchMethod'.
## [3.25.2]
- Improved Workers system to accept a list of works
## [3.25.1]
- Improved the log system to display the tag used in the controller that was created.
## [3.25.0] - Big update
- Added [reload] and [reloadAll] methods to reload your Controller to original values
- Added [FullLifeCycleController] - A GetxController capable of observing all the life cycles of your application. FullLifeCycleController has the life cycles:
* onInit: called when the controller enters the application's memory
* onReady: called after onInit, when build method from widget relationed to controller is done.
* onClose: called when controller is deleted from memory.
* onPaused: called when the application is not currently visible to the user, and running in the background.
* onInactive: called when the application is in an inactive state and is not receiving user input, when the user receives a call, for example
* onResumed: The application is now visible and in the foreground
* onDetached: The application is still hosted on a flutter engine but is detached from any host views.
* didChangeMetrics: called when the window size is changed
- Added SuperController, a complete life circle controller with StateMixin
- Improve Iterable Rx Api. Now, you can to use dart List, Map and Set as reactive, like: List<String> names = <String>['juan', 'pedro', 'maria'].obs;
- Added assign and assignAll extensions to default dart List
- Added parameters options from Get.toNamed, Get.offNamed, and Get.offAllNamed (@enghitalo)
- Improve Rx disposal logic to completely prevent memory leaks
- Improve Capitalize methods from GetUtils (@eduardoflorence)
- Prevent a close snackbar from close a Screen with double tap (@eduardoflorence)
- Includes GetLifeCycleBase mixin on delete/dispose (@saviogrossi)
- Added internacionalization example to sample app (@rodriguesJeff)
- Added headers to Graphql query and mutation(@asalvi0)
- Added translation with parameter extension (@CpdnCristiano)
- Added Get.parameter access to Middleware (@eduardoflorence)
- Fix RxBool typo (@emanuelmutschlechner)
- Added Filter to GetBuilder
- Added debouce to GetBuilder update
- Added ability to insert an Enum, class, or type of an object as a GetBuilder's Id
- Improve upload time from GetConnect
- Create minified version to DartPad(@roipeker)
- Suggested to use `Get.to(() => Page())` instead of `Get.to(Page())`.
- Added more status codes to GetConnect (@romavic)
- Fix and improve docs: @unacorbatanegra, @lsm, @nivisi, @ThinkDigitalSoftware, @martwozniak, @UsamaElgendy, @@DominusKelvin, @jintak0401, @goondeal
## [3.24.0]
- GetWidget has been completely redesigned.
... ...
![](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).*
*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).*
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
... ... @@ -136,7 +136,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Clicks: " + c.count.string))),
// Reemplace el Navigator.push de 8 líneas por un simple Get.to(). No necesitas contexto
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ...
![](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).**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![likes](https://badges.bar/get/likes)](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="Achetez moi un cafe" 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)
- [A Propos de Get](#a-propos-de-get)
- [Installation](#installation)
- [L'application 'Counter' avec GetX](#application-counter-avec-getx)
- [Les trois pilliers](#les-trois-pilliers)
- [Gestion d'état (State management)](#gestion-d-etat)
- [Gestionnaire d'état réactif (Reactive State Manager)](#gestionnaire-d-etat-reactif)
- [Plus de détails sur la gestion d'état](#plus-de-details-sur-la-gestion-d-etat)
- [Gestion de route](#gestion-de-route)
- [Plus de détails sur la gestion de route](#plus-de-details-sur-la-gestion-de-route)
- [Gestion des dépendances](#gestion-des-dependances)
- [Plus de détails sur la gestion des dépendances](#plus-de-details-sur-la-gestion-des-dependances)
- [Utils](#utils)
- [Internationalization](#internationalization)
- [Traductions](#traductions)
- [Utiliser les traductions](#utiliser-les-traductions)
- [Locales](#locales)
- [Changer la locale](#changer-la-locale)
- [Locale du Système](#locale-du-systeme)
- [Changer le Thème](#changer-le-theme)
- [GetConnect](#getconnect)
- [Configuration par défaut](#configuration-par-defaut)
- [Configuration personnalisée](#configuration-personnalisee)
- [Middleware GetPage](#middleware-getpage)
- [Priority](#priority)
- [Redirect](#redirect)
- [onPageCalled](#onpagecalled)
- [OnBindingsStart](#onbindingsstart)
- [OnPageBuildStart](#onpagebuildstart)
- [OnPageBuilt](#onpagebuilt)
- [OnPageDispose](#onpagedispose)
- [Autres APIs](#autres-apis)
- [Paramètres globaux et configurations manuelles facultatifs](#parametres-globaux-et-configurations-manuelles-facultatifs)
- [State Widgets Locaux](#state-widgets-locaux)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [Conseils utiles](#conseils-utiles)
- [GetView](#getview)
- [GetResponsiveView](#getresponsiveview)
- [Guide d'utilisation](#guide-d-utilisation)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [Changements par rapport à 2.0](#changements-par-rapport-a-20)
- [Pourquoi Getx?](#pourquoi-getx)
- [Communité](#communite)
- [Chaînes communautaires](#chaines-communautaires)
- [Comment contribuer](#comment-contribuer)
- [Articles et videos](#articles-et-videos)
# A Propos de Get
- GetX est une solution extra-légère et puissante pour Flutter. Il combine une gestion d'état (state management) de haute performance, une injection de dépendances (dependency injection) intelligente et une gestion de route (route management) rapide et pratique.
- GetX a 3 principes de base. Cela signifie que ces principes sont les priorités pour toutes les ressources de la bibliothèque GetX: **PRODUCTIVITÉ, PERFORMANCE ET ORGANIZATION.**
- **PERFORMANCE:** GetX se concentre sur la performance et la consommation minimale de ressources. GetX n'utilise ni Streams ni ChangeNotifier.
- **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.
**Il est possible d'entièrement réutiliser votre code écrit sur le frontend, pour le backend avec [Get Server](https://github.com/jonataslaw/get_server)**.
**De plus, l'ensemble du processus de développement peut être complètement automatisé, à la fois sur le serveur et sur le front-end avec [Get CLI](https://github.com/jonataslaw/get_cli)**.
**De plus, pour augmenter encore votre productivité, nous avons l'[extension pour VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) et l'[extension pour Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**
# Installation
Ajoutez Get à votre fichier pubspec.yaml:
```yaml
dependencies:
get:
```
Importez Get dans les fichiers dans lesquels il doit être utilisé:
```dart
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
```dart
void main() => runApp(GetMaterialApp(home: Home()));
```
- Note: cela ne modifie pas le MaterialApp de Flutter, GetMaterialApp n'est pas un MaterialApp modifié, il s'agit simplement d'un widget préconfiguré, qui a le MaterialApp par défaut comme enfant (child: ). Vous pouvez le configurer manuellement, mais ce n'est certainement pas nécessaire. GetMaterialApp créera des routes, les injectera, injectera les traductions, injectera tout ce dont vous avez besoin pour la navigation de routes. Si vous utilisez Get uniquement pour la gestion de l'état (State management) ou la gestion des dépendances (DI), il n'est pas nécessaire d'utiliser GetMaterialApp. GetMaterialApp est nécessaire pour les routes, les 'snackbars', l'internationalisation, les 'bottomSheets', les dialogues et les API de haut niveau liés aux routes et à l'absence de 'context'.
- Note²: Cette étape n'est nécessaire que si vous allez utiliser la gestion de routes (Get.to(), Get.back(), etc). Si vous ne l'utiliserez pas, il n'est pas nécessaire de faire l'étape 1.
- 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".
```dart
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
```
- Step 3:
Créez votre Vue, utilisez StatelessWidget et économisez de la RAM, avec Get, vous n'aurez peut-être plus besoin d'utiliser StatefulWidget.
```dart
class Home extends StatelessWidget {
@override
Widget build(context) {
// Instanciez votre classe en utilisant Get.put() pour le rendre disponible pour tous les routes "descendantes".
final Controller c = Get.put(Controller());
return Scaffold(
// Utilisez Obx(()=> pour mettre à jour Text() chaque fois que count est changé.
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// Remplacez les 8 lignes Navigator.push par un simple Get.to(). Vous n'avez pas besoin de '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 {
// Vous pouvez demander à Get de trouver un contrôleur utilisé par une autre page et de vous y rediriger.
final Controller c = Get.find();
@override
Widget build(context){
// Accéder à la variable 'count' qui est mise à jour
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
```
Résultat:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
C'est un projet simple mais il montre déjà à quel point Get est puissant. Au fur et à mesure que votre projet se développe, cette différence deviendra plus significative.
Get a été conçu pour fonctionner avec des équipes, mais il simplifie le travail d'un développeur individuel.
Améliorez vos délais, livrez tout à temps sans perte de performances. Get n'est pas pour tout le monde, mais si vous vous êtes identifié à cette phrase, Get est fait pour vous!
# Les trois pilliers
## Gestion d Etat
Get a deux gestionnaires d'état différents: le gestionnaire d'état simple (nous l'appellerons GetBuilder) et le gestionnaire d'état réactif (GetX / Obx).
### Gestionnaire d Etat Reactif
La programmation réactive peut aliéner de nombreuses personnes car on dit qu'elle est compliquée. GetX fait de la programmation réactive quelque chose d'assez simple:
- Vous n'aurez pas besoin de créer des StreamControllers.
- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable
- Vous n'aurez pas besoin de créer une classe pour chaque état.
- Vous n'aurez pas besoin de créer un 'get' pour une valeur initiale.
- Vous n'aurez pas besoin d'utiliser des générateurs de code
La programmation réactive avec Get est aussi simple que d'utiliser setState.
Imaginons que vous ayez une variable 'name' et que vous souhaitiez que chaque fois que vous la modifiez, tous les widgets qui l'utilisent soient automatiquement modifiés.
Voici votre variable:
```dart
var name = 'Jonatas Borges';
```
Pour la rendre observable, il vous suffit d'ajouter ".obs" à la fin:
```dart
var name = 'Jonatas Borges'.obs;
```
Et dans l'interface utilisateur, lorsque vous souhaitez afficher cette valeur et mettre à jour l'écran chaque fois qu'elle change, faites simplement:
```dart
Obx(() => Text("${controller.name}"));
```
C'est _tout_. Si simple que ca.
### 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.**
Vous pourrez vous faire une meilleure idée de la puissance de GetX.
## Gestion de route
Si vous envisagez d'utiliser des routes/snackbars/dialogs/bottomsheets sans 'context', GetX est également excellent pour vous, voyez par vous-même:
Ajoutez "Get" avant votre MaterialApp, en le transformant en GetMaterialApp
```dart
GetMaterialApp( // Avant: MaterialApp(
home: MyHome(),
)
```
Accédez à un nouvel écran:
```dart
Get.to(ÉcranSuivant());
```
Accédez au nouvel écran par le nom. Voir plus de détails sur les itinéraires nommés (named routes) [ici](./documentation/fr_FR/route_management.md#navigation-avec-des-itinraires-nomms)
```dart
Get.toNamed('/details');
```
Pour fermer des snackbars, dialogs, bottomsheets, ou tout ce que vous auriez normalement fermé avec Navigator.pop(context);
```dart
Get.back();
```
Pour aller à l'écran suivant avec aucune option pour revenir à l'écran précédent (pour une utilisation dans SplashScreens, écrans de connexion, etc.)
```dart
Get.off(NextScreen());
```
Pour aller à l'écran suivant et annuler tous les itinéraires précédents (utile dans les paniers d'achat en ligne, les sondages et les tests)
```dart
Get.offAll(NextScreen());
```
Avez-vous remarqué que vous n'avez eu besoin d'utiliser 'context' pour aucune de ces opérations? C'est l'un des plus grands avantages de l'utilisation de la gestion de route avec Get. Avec cela, vous pouvez appeler toutes ces méthodes à partir de votre classe de contrôleur, sans soucis.
### Plus de details sur la gestion de route
**Get fonctionne avec des itinéraires nommés (named routes) et offre également un contrôle plus granulaire de vos routes! Il y a une documentation approfondie [ici](./documentation/fr_FR/route_management.md)**
## Gestion des dependances
Get a un gestionnaire de dépendances (dependency manager) simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou Controller avec seulement 1 ligne de code, pas de 'context' Provider, pas d'inheritedWidget:
```dart
Controller controller = Get.put(Controller()); // Au lieu de Controller controller = Controller();
```
- Remarque: Si vous utilisez le gestionnaire d'état de Get, accordez plus d'attention à l'API 'Bindings', qui facilitera la connexion de vos Vues à vos contrôleurs.
Au lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get, ce qui la rendra disponible dans toute votre application.
Vous pouvez donc utiliser votre contrôleur (ou classe Bloc) normalement.
**Conseil:** La gestion des dépendances est découplée des autres parties du package, donc si, par exemple, votre application utilise déjà un gestionnaire d'état (n'importe lequel, peu importe), vous n'avez pas besoin de tout réécrire, vous pouvez l'utiliser avec l'injection de dépendance de Get sans aucun problème.
```dart
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.
```
Et puis vous pourrez récupérer les données de votre contrôleur obtenu précédemment:
```dart
Text(controller.textFromApi);
```
### Plus de details sur la gestion des dependances
**Trouvez une explication plus détaillée sur la gestion des dépendances [ici](./documentation/fr_FR/dependency_management.md)**
# Utils
## Internationalization
### Traductions
Les traductions sont enregistrées sous forme de dictionaire clé-valeur simple.
Pour ajouter des traductions, créez une classe qui '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',
}
};
}
```
#### Utiliser les traductions
Ajouter juste `.tr` à la clé et elle sera traduite selon la valeur actuelle `Get.locale` et de `Get.fallbackLocale`.
```dart
Text('title'.tr);
```
#### Utiliser les traductions avec le singulier et le pluriel
```dart
var products = [];
Text('cléAuSingulier'.trPlural('cléAuPluriel', products.length, Args));
```
#### Utiliser les traductions avec paramètres
```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
'Locales' signifie lieux.
Pour definir les traductions, passer les paramètres 'locale' et 'translations' à GetMaterialApp.
```dart
return GetMaterialApp(
translations: Messages(), // Vos traductions
locale: Locale('en', 'US'), // Les traductions seront faites dans cette 'locale' (langue)
fallbackLocale: Locale('en', 'UK'), // definit le 'language de secours' au cas oú un language invalide est sélectionné.
);
```
#### Changer la locale
Appelez `Get.updateLocale (locale)` pour mettre à jour la locale. Les traductions utilisent alors automatiquement la nouvelle langue.
```dart
var locale = Locale('en', 'US');
Get.updateLocale(locale);
```
#### Locale du systeme
Pour lire les paramètres régionaux ('locales') du système, vous pouvez utiliser `Get.deviceLocale`.
```dart
return GetMaterialApp(
locale: Get.deviceLocale,
);
```
## Changer le Theme
Veuillez ne pas utiliser de widget de niveau supérieur à `GetMaterialApp` pour le mettre à jour. Cela peut créer des clés ('keys') en double. Beaucoup de gens sont habitués à l'approche préhistorique de la création d'un widget "ThemeProvider" juste pour changer le thème de votre application, et ce n'est certainement PAS nécessaire avec **GetX ™**.
Vous pouvez créer votre thème personnalisé et l'ajouter simplement dans `Get.changeTheme` sans aucune préconfiguration pour cela:
```dart
Get.changeTheme(ThemeData.light());
```
Si vous voulez créer quelque chose comme un bouton qui change le thème dans `onTap`, vous pouvez combiner deux API **GetX ™** pour cela:
- L'API qui vérifie si le "Thème" sombre est utilisé.
- Et l'API de changement de thème, vous pouvez simplement le mettre dans un 'onPressed':
```dart
Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
```
Lorsque 'onPressed' est appelé, si `.darkmode` est activé, il passera au _thème clair_, et lorsque le _thème clair_ est actif, il passera au _thème sombre_.
## GetConnect
GetConnect est un moyen facile de communiquer de votre backend à votre frontend avec http ou websockets.
### Configuration par defaut
Vous pouvez simplement 'extends' GetConnect et utiliser les méthodes GET / POST / PUT / DELETE / SOCKET pour communiquer avec votre API Rest ou vos 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');
}
}
```
### 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
class HomeProvider extends GetConnect {
@override
void onInit() {
// Toute 'Request' passera à jsonEncode donc CasesModel.fromJson()
httpClient.defaultDecoder = CasesModel.fromJson;
httpClient.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
httpClient.addRequestModifier((request) {
request.headers['apikey'] = '12345678';
return request;
});
// Même si le serveur envoie des données avec le pays "Brésil",
// cela ne sera jamais affiché aux utilisateurs, car vous supprimez
// ces données de la réponse, même avant que la réponse ne soit délivrée
httpClient.addResponseModifier<CasesModel>((request, response) {
CasesModel model = response.body;
if (model.countries.contains('Brazil')) {
model.countries.remove('Brazil');
}
});
httpClient.addAuthenticator((request) async {
final response = await get("http://yourapi/token");
final token = response.body['token'];
// Définit l'en-tête
request.headers['Authorization'] = "$token";
return request;
});
// L'Autenticator sera appelé 3 fois si HttpStatus est HttpStatus.unauthorized
httpClient.maxAuthRetries = 3;
}
@override
Future<Response<CasesModel>> getCases(String path) => get(path);
}
```
## Middleware GetPage
GetPage a maintenant une nouvelle propriété qui prend une liste de GetMiddleWare et les exécute dans l'ordre spécifique.
**Note**: Lorsque GetPage a un Middleware, tous les enfants de cette page auront automatiquement les mêmes middlewares.
### Priority
L'ordre des middlewares à exécuter peut être défini par la priorité dans GetMiddleware.
```dart
final middlewares = [
GetMiddleware(priority: 2),
GetMiddleware(priority: 5),
GetMiddleware(priority: 4),
GetMiddleware(priority: -8),
];
```
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( ) {
final authService = Get.find<AuthService>();
return authService.authed.value ? null : RouteSettings(name: '/login');
}
```
### onPageCalled
Cette fonction sera appelée lorsque cette page sera appelée.
Vous pouvez l'utiliser pour changer quelque chose sur la page ou lui donner une nouvelle page.
```dart
GetPage onPageCalled(GetPage page) {
final authService = Get.find<AuthService>();
return page.copyWith(title: 'Welcome ${authService.UserName}');
}
```
### OnBindingsStart
Cette fonction sera appelée juste avant l'initialisation des liaisons ('bidings').
Ici, vous pouvez modifier les liaisons de cette page.
```dart
List<Bindings> onBindingsStart(List<Bindings> bindings) {
final authService = Get.find<AuthService>();
if (authService.isAdmin) {
bindings.add(AdminBinding());
}
return bindings;
}
```
### OnPageBuildStart
Cette fonction sera appelée juste après l'initialisation des liaisons ('bidings').
Ici, vous pouvez faire quelque chose après avoir créé les liaisons et avant de créer le widget de page.
```dart
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
print('les liaisons sont prêtes');
return 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
Cette fonction sera appelée juste après avoir disposé tous les objets associés (contrôleurs, vues, ...) à la page.
## Autres APIs
```dart
// donne les arguments actuels de currentScreen
Get.arguments
// donne le nom de l'itinéraire précédent
Get.previousRoute
// donne la route brute d'accès par exemple, rawRoute.isFirst()
Get.rawRoute
// donne accès à l'API de routing de GetObserver
Get.routing
// vérifier si le snackbar est ouvert
Get.isSnackbarOpen
// vérifier si la boîte de dialogue est ouverte
Get.isDialogOpen
// vérifie si la bottomSheet est ouverte
Get.isBottomSheetOpen
// supprime une route.
Get.removeRoute()
// retourne à plusieurs reprises jusqu'à ce que le prédicat retourne 'true'.
Get.until()
// passe à la route suivante et supprime toutes les routes précédentes jusqu'à ce que le prédicat retourne 'true'.
Get.offUntil()
// passe à la route nommée suivante et supprime toutes les routes précédentes jusqu'à ce que le prédicat retourne 'true'.
Get.offNamedUntil()
// Vérifie sur quelle plate-forme l'application s'exécute
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
// Vérifie le type d'appareil
GetPlatform.isMobile
GetPlatform.isDesktop
// Toutes les plates-formes sont prises en charge indépendamment, dans le Web!
// Vous pouvez dire si vous utilisez un navigateur
// sur Windows, iOS, OSX, Android, etc.
GetPlatform.isWeb
// Équivaut à: MediaQuery.of(context).size.height,
// mais immuable.
Get.height
Get.width
// Donne le 'context' actuel de 'Navigator'.
Get.context
// Donne le contexte du snackbar / dialogue / bottomsheet au premier plan, n'importe où dans votre code.
Get.contextOverlay
// Remarque: les méthodes suivantes sont des extensions sur le 'context'. Puisque vous
// avez accès au contexte à n'importe quel endroit de votre interface utilisateur, vous pouvez l'utiliser n'importe où dans le code de l'interface utilisateur
// Si vous avez besoin d'une hauteur / largeur variable (comme les fenêtres de bureau ou de navigateur qui peuvent être mises à l'échelle), vous devrez utiliser le contexte.
context.width
context.height
// Vous donne le pouvoir de définir la moitié de l'écran, un tiers de celui-ci et ainsi de suite.
// Utile pour les applications responsives.
// paramètre dividedBy (double) optionnel - par défaut: 1
// paramètre reducedBy (double) facultatif - par défaut: 0
context.heightTransformer ()
context.widthTransformer ()
/// Similaire à MediaQuery.of(context).size
context.mediaQuerySize()
/// Similaire à MediaQuery.of(context).padding
context.mediaQueryPadding()
/// Similaire à MediaQuery.of(context).viewPadding
context.mediaQueryViewPadding()
/// Similaire à MediaQuery.of(context).viewInsets;
context.mediaQueryViewInsets()
/// Similaire à MediaQuery.of(context).orientation;
context.orientation()
/// Vérifie si l'appareil est en mode paysage
context.isLandscape()
/// Vérifie si l'appareil est en mode portrait
context.isPortrait()
/// Similaire à MediaQuery.of(context).devicePixelRatio;
context.devicePixelRatio()
/// Similaire à MediaQuery.of(context).textScaleFactor;
context.textScaleFactor()
/// Obtenir le côté le plus court de l'écran
context.mediaQueryShortestSide()
/// Vrai si la largeur est supérieure à 800p
context.showNavbar()
/// Vrai si le côté le plus court est inférieur à 600p
context.isPhone()
/// Vrai si le côté le plus court est plus grand que 600p
context.isSmallTablet()
/// Vrai si le côté le plus court est plus grand que 720p
context.isLargeTablet()
/// Vrai si l'appareil actuel est une tablette
context.isTablet()
/// Renvoie une valeur <T> en fonction de la taille de l'écran
/// peut donner une valeur pour:
/// watch: si le côté le plus court est inférieur à 300
/// mobile: si le côté le plus court est inférieur à 600
/// tablette: si le côté le plus court est inférieur à 1200
/// bureautique: si la largeur est supérieure à 1200
context.responsiveValue<T>()
```
### Parametres globaux et configurations manuelles facultatifs
GetMaterialApp configure tout pour vous, mais si vous souhaitez configurer Get manuellement:
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
```
Vous pourrez également utiliser votre propre middleware dans `GetObserver`, cela n'influencera rien.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // Ici
],
);
```
Vous pouvez créer _Global Settings_ pour `Get`. Ajoutez simplement `Get.config` à votre code avant de changer de route.
Ou faites-le directement dans votre `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
)
```
Vous pouvez éventuellement rediriger tous les messages de journalisation (logging) de `Get`.
Si vous souhaitez utiliser votre propre package de journalisation préféré,
et souhaitez capturer les logs là-bas:
```dart
GetMaterialApp(
enableLog: true,
logWriterCallback: localLogWriter,
);
void localLogWriter(String text, {bool isError = false}) {
// transmettez le message à votre package de journalisation préféré ici
// veuillez noter que même si enableLog: false, les messages du journal seront poussés dans ce 'callback'
// vérifiez le 'flag' si vous le souhaitez via GetConfig.isLogEnable
}
```
### State Widgets Locaux
Ces Widgets vous permettent de gérer une valeur unique, et de garder l'état éphémère et localement.
Nous avons des saveurs pour réactif et simple.
Par exemple, vous pouvez les utiliser pour basculer obscureText dans un `TextField`, peut-être créer un
Panneau extensible, ou peut-être modifier l'index actuel dans `BottomNavigationBar` tout en modifiant le contenu
de 'body' dans un `Scaffold`.
#### ValueBuilder
Une simplification de `StatefulWidget` qui fonctionne avec un callback `.setState` qui prend la valeur mise à jour.
```dart
ValueBuilder<bool>(
initialValue: false,
builder: (value, updateFn) => Switch(
value: value,
onChanged: updateFn, // même signature! vous pouvez utiliser (newValue) => updateFn (newValue)
),
// si vous devez appeler quelque chose en dehors de la méthode du builder.
onUpdate: (value) => print("Valeur mise à jour: $value"),
onDispose: () => print("Widget détruit"),
),
```
#### 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?
```dart
ObxValue((data) => Switch(
value: data.value,
onChanged: data, // Rx a une fonction _callable_! Vous pouvez utiliser (flag) => data.value = flag,
),
false.obs,
),
```
## Conseils utiles
`.obs`ervables (également appelés types _Rx_) ont une grande variété de méthodes et d'opérateurs internes.
> Il est très courant de croire qu'une propriété avec `.obs` ** EST ** la valeur réelle ... mais ne vous y trompez pas!
> Nous évitons la déclaration Type de la variable, car le compilateur de Dart est assez intelligent, et le code
> semble plus propre, mais:
```dart
var message = 'Hello world'.obs;
print( 'Message "$message" est de Type ${message.runtimeType}');
```
Bien que `message` _prints_ la vraie valeur du String, le Type est **RxString**!
Donc, vous ne pouvez pas faire `message.substring( 0, 4 )`.
Vous devez utiliser la vraie `valeur` dans _observable_:
La façon "la plus utilisée" est `.value`, mais, que vous pouviez aussi...
```dart
final name = 'GetX'.obs;
// "met à jour" le flux, uniquement si la valeur est différente de la valeur actuelle.
name.value = 'Hey';
// Toutes les propriétés Rx sont "appelables" et renvoie la nouvelle valeur.
// mais cette approche n'accepte pas `null`, l'interface utilisateur ne sera pas reconstruite.
name('Hello');
// est comme un getter, affiche `Hello`.
name() ;
/// nombres:
final count = 0.obs;
// Vous pouvez utiliser toutes les opérations non mutables à partir de num primitives!
count + 1;
// Fais attention! ceci n'est valable que si `count` n'est pas final, mais var
count += 1;
// Vous pouvez également comparer avec des valeurs:
count > 2;
/// booleans:
final flag = false.obs;
// bascule la valeur entre true / false
flag.toggle();
/// tous les types:
// Définit la `valeur` sur null.
flag.nil();
// Toutes les opérations toString (), toJson () sont transmises à la `valeur`
print( count ); // appelle `toString ()` à l'intérieur de RxInt
final abc = [0,1,2].obs;
// Convertit la valeur en un Array json, affiche RxList
// Json est pris en charge par tous les types Rx!
print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
// RxMap, RxList et RxSet sont des types Rx spéciaux, qui étendent leurs types natifs.
// mais vous pouvez travailler avec une liste comme une liste régulière, bien qu'elle soit réactive!
abc.add(12); // pousse 12 dans la liste et MET À JOUR le flux.
abc[3]; // comme Lists, lit l'index 3.
// l'égalité fonctionne avec le Rx et la valeur, mais hashCode est toujours pris à partir de la valeur
final number = 12.obs;
print( number == 12 ); // retource > true
/// Modèles Rx personnalisés:
// toJson (), toString () sont différés à l'enfant, vous pouvez donc implémenter 'override' sur eux, et print() l'observable directement.
class User {
String name, last;
int age;
User({this.name, this.last, this.age});
@override
String toString() => '$name $last, $age ans';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
// `user` est" réactif ", mais les propriétés à l'intérieur NE SONT PAS!
// Donc, si nous changeons une variable à l'intérieur ...
user.value.name = 'Roi';
// Le widget ne se reconstruira pas !,
// `Rx` n'a aucun indice lorsque vous changez quelque chose à l'intérieur de l'utilisateur.
// Donc, pour les classes personnalisées, nous devons "notifier" manuellement le changement.
user.refresh();
// ou utiliser `update()`!
user.update((value){
value.name='Roi';
});
print( user );
```
#### GetView
J'adore ce widget. Si simple, mais si utile!
C'est un widget `const Stateless` qui a un getter` controller` pour un `Controller` enregistré, c'est tout.
```dart
class AwesomeController extends GetxController {
final String title = 'My Awesome View';
}
// N'oubliez PAS de passer le `Type` que vous avez utilisé pour enregistrer votre contrôleur!
class AwesomeView extends GetView<AwesomeController> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Text(controller.title), // appelez `controller.quelqueChose`
);
}
}
```
#### GetResponsiveView
Étendez ce widget pour créer une vue réactive.
ce widget contient la propriété `screen` qui a toutes les
informations sur la taille et le type de l'écran.
##### Guide d utilisation
Vous avez deux options pour le créer:
- avec la méthode `builder` vous renvoyez le widget à construire.
- avec les méthodes `desktop`,` tablet`, `phone`,` watch`. la méthode spécifique sera exécutée lorsque le type d'écran correspond à la méthode.
Lorsque l'écran est [ScreenType.Tablet], la méthode `tablet` sera exécutée et ainsi de suite.
**Note:** Si vous utilisez cette méthode, veuillez définir la propriété `alwaysUseBuilder` à `false`
Avec la propriété `settings`, vous pouvez définir la limite de largeur pour les types d'écran.
![exemple](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
Code pour cet écran
[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
#### GetWidget
La plupart des gens n'ont aucune idée de ce widget ou confondent totalement son utilisation.
Le cas d'utilisation est très rare, mais très spécifique: il `met en cache` un contrôleur.
En raison du _cache_, ne peut pas être un `const Stateless`.
> Alors, quand avez-vous besoin de "mettre en cache" un contrôleur?
Si vous utilisez, une autre fonctionnalité "pas si courante" de **GetX**: `Get.create()`.
`Get.create(()=>Controller())` générera un nouveau `Controller` chaque fois que vous appelez
`Get.find<Controller>()`.
C'est là que `GetWidget` brille ... comme vous pouvez l'utiliser, par exemple,
pour conserver une liste de <Todo>s. Donc, si le widget est "reconstruit", il conservera la même instance de contrôleur.
#### 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.
Il notifie simplement le **GetX** Dependency Injection system, que cette sous-classe
**ne peut pas** être supprimé de la mémoire.
Donc est très utile pour garder vos "Services" toujours à portée de main et actifs avec `Get.find()`. Comme:
`ServiceAPI`, `ServiceDeSauvegarde`, `ServiceDeCaching`.
```dart
Future<void> main() async {
await initServices(); /// Attend l'initialisation des services.
runApp(SomeApp());
}
/// Est une démarche intelligente pour que vos services s'initialisent avant d'exécuter l'application Flutter.
/// car vous pouvez contrôler le flux d'exécution (peut-être devez-vous charger une configuration de thème,
/// apiKey, langue définie par l'utilisateur ... donc chargez SettingService avant d'exécuter ApiService.
/// donc GetMaterialApp () n'a pas besoin de se reconstruire et prend les valeurs directement.
void initServices() async {
print('starting services ...');
/// C'est ici que vous mettez get_storage, hive, shared_pref initialization.
/// ou les connexions moor, ou autres choses async.
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('Tous les services ont démarré...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType retarde de 2 sec');
await 2.delay();
print('$runtimeType prêts!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print("$runtimeType retarde d'1 sec");
await 1.delay();
print('$runtimeType prêts!');
}
}
```
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`.
# Changements par rapport a 2.0
1- Types Rx:
| Avant | Après |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
| MapX | `RxMap` |
| ListX | `RxList` |
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
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:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
Maintenant:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
```
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();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
# Pourquoi Getx?
1- Plusieurs fois après une mise à jour de Flutter, plusieurs de vos packages seront invalides. Parfois, des erreurs de compilation se produisent, des erreurs apparaissent souvent pour lesquelles il n'y a toujours pas de réponses, et le développeur doit savoir d'où vient l'erreur, suivre l'erreur, puis seulement essayer d'ouvrir un problème dans le référentiel correspondant et voir son problème résolu. Get centralise les principales ressources pour le développement (gestion des états, des dépendances et des routes), vous permettant d'ajouter un package unique à votre pubspec et de commencer à travailler. Après une mise à jour Flutter, la seule chose à faire est de mettre à jour la dépendance Get et de vous mettre au travail. Get résout également les problèmes de compatibilité. Combien de fois une version d'un package n'est pas compatible avec la version d'un autre, parce que l'une utilise une dépendance dans une version et l'autre dans une autre version? Ce n'est pas non plus un problème avec Get, car tout est dans le même package et est entièrement compatible.
2- Flutter est facile, Flutter est incroyable, mais Flutter a encore quelques règles standard qui peuvent être indésirables pour la plupart des développeurs, comme `Navigator.of (context) .push (context, builder [...]`. Get simplifie le développement. Au lieu de écrire 8 lignes de code pour simplement appeler une route, vous pouvez simplement le faire: `Get.to (Home ())` et vous avez terminé, vous passerez à la page suivante. Les URL Web dynamiques sont une chose vraiment pénible à voir avec Flutter actuellement, et cela avec GetX est stupidement simple. La gestion des états dans Flutter et la gestion des dépendances sont également quelque chose qui génère beaucoup de discussions, car il y a des centaines de modèles dans la pub. Mais rien n'est aussi simple que d'ajouter un ".obs" à la fin de votre variable, et placez votre widget dans un Obx, et c'est tout, toutes les mises à jour de cette variable seront automatiquement mises à jour à l'écran.
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.
# 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** |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [![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) |
## Comment contribuer
_Voulez-vous contribuer au projet? Nous serons fiers de vous mettre en avant comme l'un de nos collaborateurs. Voici quelques points sur lesquels vous pouvez contribuer et améliorer encore Get (et Flutter)._
- Aider à traduire les 'Readme's dans d'autres langues.
- Ajout de documentation au readme (beaucoup de fonctions de Get n'ont pas encore été documentées).
- Rédiger des articles ou réaliser des vidéos pour apprendre à utiliser Get (ils seront insérés dans le Readme et à l'avenir dans notre Wiki).
- Offrir des PRs pour code / tests.
- Ajouter de nouvelles fonctions.
Toute contribution est bienvenue!
## Articles et videos
- [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.
... ...
![](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).**
**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)**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
... ... @@ -148,7 +148,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// Ganti 8 baris Navigator.push menggunan Get.to() agar lebih sederhana. Anda tidak perlu `context`.
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**언어: [우르두어](README.ur-PK.md), [영어](README.md), [인도네시아 인](README.id-ID.md), [중국어](README.zh-cn.md), [브라질 포르투칼어](README.pt-br.md), [스페인어](README-es.md), [러시아어](README.ru.md), [폴란드어](README.pl.md), 한국어(이파일).**
**언어: [우르두어](README.ur-PK.md), [영어](README.md), [인도네시아 인](README.id-ID.md), [중국어](README.zh-cn.md), [브라질 포르투칼어](README.pt-br.md), [스페인어](README-es.md), [러시아어](README.ru.md), [폴란드어](README.pl.md), 한국어(이파일), [French](README-fr.md)**
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
... ... @@ -16,9 +16,9 @@
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
- [Get에 대하여](#Get에-대하여)
- [Get에 대하여](#get에-대하여)
- [설치](#설치)
- [GetX를 사용한 Counter 앱](#GetX를-사용한-Counter-앱)
- [GetX를 사용한 Counter 앱](#getx를-사용한-counter-앱)
- [세가지 주요점](#세가지-주요점)
- [상태 관리](#상태-관리)
- [반응형 상태 관리자](#반응형-상태-관리자)
... ... @@ -46,7 +46,7 @@
- [OnPageBuildStart](#onpagebuildstart)
- [OnPageBuilt](#onpagebuilt)
- [OnPageDispose](#onpagedispose)
- [기타 고급 API](#기타-고급-API)
- [기타 고급 API](#기타-고급-api)
- [선택적 전역 설정과 수동 구성](#선택적-전역-설정과-수동-구성)
- [지역 상태 위젯들](#지역-상태-위젯들)
- [ValueBuilder](#valuebuilder)
... ... @@ -55,8 +55,8 @@
- [GetView](#getview)
- [GetWidget](#getwidget)
- [GetxService](#getxservice)
- [2.0의 주요 변경점](#2.0의-주요-변경점)
- [왜-Getx인가?](#왜-Getx인가?)
- [2.0의 주요 변경점](#20의-주요-변경점)
- [왜 Getx인가?](#왜-getx인가)
- [커뮤니티](#커뮤니티)
- [커뮤니티 채널](#커뮤니티-채널)
- [기여하는 방법](#기여하는-방법)
... ... @@ -145,7 +145,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// 8줄의 Navigator.push를 간단한 Get.to()로 변경합니다. context는 필요없습니다.
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ... @@ -188,7 +188,7 @@ Get은 두가지 상태 관리자가 있습니다: 단순 상태관리자(GetBui
- 각 변수에 대해 StreamBuilder를 만들 필요가 없습니다.
- 각각의 상태(state)를 위한 클래스를 만들 필요가 없습니다.
- 초기값을 위한 get이 필요하지 않습니다.
- 코드 생성기를 사용할 필요가 없스빈다.
- 코드 생성기를 사용할 필요가 없습니다.
Get의 반응형 프로그램은 setState를 사용하는 것 만큼 쉽습니다.
... ... @@ -216,7 +216,7 @@ Obx(() => Text("${controller.name}"));
### 상태 관리에 대한 자세한 내용
**상태 관리에 대한 자세한 설명은 [여기](./documentation/en_US/state_management.md)를 보십시오. 여기에서 더 많은 예제와 단순 상태 관리자와 반응형 상태 관리자의 차이점을 볼 수 있습니다.**
**상태 관리에 대한 자세한 설명은 [여기](./documentation/kr_KO/state_management.md)를 보십시오. 여기에서 더 많은 예제와 단순 상태 관리자와 반응형 상태 관리자의 차이점을 볼 수 있습니다.**
GetX 능력에 대한 좋은 아이디어를 얻을 수 있습니다.
... ... @@ -969,7 +969,7 @@ class SettingsService extends GetxService {
1- Rx 타입들:
| 이전 | 이후 |
| 이전 | 이후 |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**Languages: English (this file), [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).**
**Languages: English (this file), [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)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
... ... @@ -119,7 +119,7 @@ void main() => runApp(GetMaterialApp(home: Home()));
```
- Note: this does not modify the MaterialApp of the Flutter, GetMaterialApp is not a modified MaterialApp, it is just a pre-configured Widget, which has the default MaterialApp as a child. You can configure this manually, but it is definitely not necessary. GetMaterialApp will create routes, inject them, inject translations, inject everything you need for route navigation. If you use Get only for state management or dependency management, it is not necessary to use GetMaterialApp. GetMaterialApp is necessary for routes, snackbars, internationalization, bottomSheets, dialogs, and high-level apis related to routes and absence of context.
- Note²: This step in only necessary if you gonna use route management (`Get.to()`, `Get.back()` and so on). If you not gonna use it then it is not necessary to do step 1
- Note²: This step is only necessary if you gonna use route management (`Get.to()`, `Get.back()` and so on). If you not gonna use it then it is not necessary to do step 1
- Step 2:
Create your business logic class and place all variables, methods and controllers inside it.
... ... @@ -149,7 +149,7 @@ class Home extends StatelessWidget {
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: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ... @@ -210,7 +210,7 @@ To make it observable, you just need to add ".obs" to the end of it:
var name = 'Jonatas Borges'.obs;
```
And in the UI, when you want to show that value and update the screen whenever tha values changes, simply do this:
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}"));
... ... @@ -916,6 +916,55 @@ user.update((value){
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
... ... @@ -924,7 +973,7 @@ 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 GetxController {
class AwesomeController extends GetController {
final String title = 'My Awesome View';
}
... ... @@ -1120,6 +1169,7 @@ 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.
... ... @@ -1133,3 +1183,4 @@ Any contribution is welcome!
- [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)
*Languages: [English](README.md), [Indonezyjski](README.id-ID.md), [Urdu](README.ur-PK.md), [Język chiński](README.zh-cn.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), [Russian](README.ru.md), Polish (Jesteś tu), [Koreański](README.ko-kr.md).*
*Languages: [English](README.md), [Indonezyjski](README.id-ID.md), [Urdu](README.ur-PK.md), [Język chiński](README.zh-cn.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), [Russian](README.ru.md), Polish (Jesteś tu), [Koreański](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)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
... ... @@ -48,14 +48,14 @@
[**Telegram (Portuguese)**](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)
# Wprowadzenie
- GetX jest bardzo lekką i potężną biblioteką do Flattera. Łączy wysoką wydajność menadżera stanu, inteligętne dodawanie dependencies i zarządzanie routami w szybki i praktyczny sposób.
- GetX jest bardzo lekką, a zarazem potężną biblioteką do Flattera. Łączy wysoką wydajność menadżera stanu, inteligętne dodawanie dependencies i zarządzanie routami w szybki i praktyczny sposób.
- GetX nie jest dla wszystkich, skupia się na jak najmniejszej konsumpcji zasobów (wydajności) ([zobacz benchmarki](https://github.com/jonataslaw/benchmarks)), używaniu łatwej skłani (produktywności) i daniu możliwości pełnego rozbicia View na z logiki biznesowej (organizacja).
- GetX która da Ci supermoce i zwiększy produktywność w tworzeniu projektu. Oszczędzi godziny zarówno początkującym jak i ekspoertom.
- GetX da Ci supermoce i zwiększy produktywność w tworzeniu projektu. Oszczędzi godziny zarówno początkującym jak i ekspertom.
- Nawiguj bez podawania `context`, używaj open `dialogs`, `snackbarów` oraz `bottomsheetów` z każdego miejsca w kodzie. Zarządzaj stanami i dodawaj dependencies w prosty i praktyczny sposób!
- Get jest bezpieczny, stabilny i aktualny. Oprócz tego oferuje szeroki zakres API, które nie są zawarte w standardowym frameworku.
- GetX nie jest przytłaczający. Ma wiele funkcjonalności pozwalajacych na rozpoczęcie programowania bez martwienia się o nic, ale wszystkie te funkcjonalności są w osobnych kontenerach będących dodane dopiero po ich użyciu. Jeśli tylko używasz menadżera stanu, tylko on będzie kompilowany. Jeśli używasz routów, lecz nic z menadżera stanu on nie będzie kompilowany. Możesz skompilować repozytorium benchmark i zobaczysz że używa tylko menadżera stanu. Aplikacje używajace Get są mniejsze niz inne ponieważ wszystkie rozwiązania GetX sa projektowane dla lekkości i wydajności. Jest to też zasługa Flutterowego AOT, które jest niesamowite i eliminuje nieużywane zasoby jak żaden inny framework.
- GetX nie jest przytłaczający. Ma wiele funkcjonalności pozwalajacych na rozpoczęcie programowania bez martwienia się zupełnie nic. Wszystkie funkcjonalności są w osobnych kontenerach, które dodawane są dopiero po ich użyciu. Jeśli tylko używasz menadżera stanu, tylko on będzie kompilowany. Jeśli używasz routów, lecz nic z menadżera stanu to nie będzie on kompilowany. Możesz skompilować repozytorium benchmark i zobaczysz że używa tylko menadżera stanu. Aplikacje używajace Get są mniejsze niz inne, ponieważ wszystkie rozwiązania GetX są projektowane z myślą o lekkości i wydajności. Jest to też zasługa Flutterowego AOT, które jest niesamowite i eliminuje nieużywane zasoby jak żaden inny framework.
**GetX zwiększa stwoja produktywność, lecz mozesz to jeszcze przyspieszyć instalując rozszerzenie [GetX extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) do swojego VSCode**. Jeszcze nie dostępne w innych IDE.
**GetX zwiększa twoja produktywność, lecz możesz to jeszcze przyspieszyć instalując rozszerzenie [GetX extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) do swojego VSCode**. Jeszcze nie dostępne w innych IDE.
# Instalacja
... ... @@ -74,7 +74,7 @@ import 'package:get/get.dart';
# Counter App z GetX
Przykładowa aplikaja tworzona domyślnie podczas kreacji nowego projektu we Flaterze ma ponad 100 lini kodu (z komentarzami). By pokazać siłę Get pokarzę jak zrobić "licznik" ze zmienianą stan z każdym kliknięciem, zmianą stron i udostępniajac stan pomiędzy ekranami. Wszystko w zorganizowany sposób dzieląc buissnes logic z view w zaledwie 26 LINI KODU WŁĄCZAJĄC W TO KOMENTARZE.
Przykładowa aplikaja tworzona domyślnie podczas kreacji nowego projektu we Flaterze ma ponad 100 lini kodu (z komentarzami). By pokazać siłę Get pokażę jak zrobić "licznik" ze zmianą stanu przy każdym kliknięciu, zmianą stron i udostępniajac stan pomiędzy ekranami. Wszystko w zorganizowany sposób dzieląc bussines logic z view w zaledwie 26 LINI KODU WŁĄCZAJĄC W TO KOMENTARZE.
-Krok 1:
Dodaj "Get" przed MaterialApp, zamieniając je na GetMaterialApp
... ... @@ -84,10 +84,10 @@ Dodaj "Get" przed MaterialApp, zamieniając je na GetMaterialApp
void main() => runApp(GetMaterialApp(home: Home()));
```
- Note: nie jest to modyfikaja MaterialApp, ponieważ GetMaterialApp nie jest zmodyfikowanym MaterialApp z Fluttera, jest tylko zkonfigurowanym Widgetem mającym domyślnie MaterialApp jako dziecko. Możesz to konfigurować ręcznie, ale nie jest to konieczne. GetMaterialApp jest niezbędne dla działania routów, snackbarów, bootomsheetów, internacjonalizacji, dialogów i wysokopoziomowych api powiązanych z routami i nieobecnościa kontekstu. Nie jest to jednak wymagane do używania zarzadzania stanem i dependencies.
- Note: nie jest to modyfikaja MaterialApp, ponieważ GetMaterialApp nie jest zmodyfikowanym MaterialApp z Fluttera, jest tylko skonfigurowanym Widgetem mającym domyślnie MaterialApp jako dziecko. Możesz to konfigurować ręcznie, ale nie jest to konieczne. GetMaterialApp jest niezbędne dla działania routów, snackbarów, bootomsheetów, internacjonalizacji, dialogów i wysokopoziomowych api powiązanych z routami i nieobecnościa kontekstu. Nie jest to jednak wymagane do używania zarzadzania stanem i dependencies.
-Krok 2:
Tworzymy klasę business logic i umieszczmy w niej wszystkie zmienne, metody oraz kontrolery. Możesz zmienić zmienna=ą na obserwowalną używajac prostego ".obs"
Tworzymy klasę business logic i umieszczmy w niej wszystkie zmienne, metody oraz kontrolery. Możesz zmienić zmiennaą na obserwowalną używajac prostego subfixu ".obs"
```dart
class Controller extends GetxController{
... ... @@ -113,7 +113,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Clicks: " + c.count.string))),
// Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ... @@ -135,11 +135,11 @@ Wynik:
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)
Jest to prosty projekt, ale już na jego przykładzie widać potęgę Get. Wzraz ze wzrostem rozmiaru aplikacji ta różnica tylko się powieksza.
Jest to prosty projekt, ale już na jego przykładzie widać potęgę Get. Wraz ze wzrostem rozmiaru aplikacji ta różnica tylko się powiększa.
Get był projektowany dla pracy z zespołem, ale równie dobrze sprawdza się w indywidualnej pracy.
Get był projektowany dla pracy z zespołem, ale równie dobrze sprawdza się w indywidualnych projektach.
Zawsze dotrzymuj deadlinów i dostarczaj swoje rozwiązania na czas bez straty na wydajności. Get nie jest dla wszystkich jak już wspominałem, ale jeśli identyfikujesz się z powyższym zdaniem Get jest dla ciebie.
Zawsze dotrzymuj deadlinów i dostarczaj swoje rozwiązania na czas bez straty na wydajności. Get nie jest dla wszystkich jak już wspominałem, ale jeśli identyfikujesz się z powyższym zdaniem Get jest właśnie dla Ciebie.
# Trzy filary
... ... @@ -151,15 +151,15 @@ Get nie jest ani lepszy, ani gorszy od innych menadżerów stanów, ale powinien
Definitywnie Get nie jest przeciwnikiem żadnego innego menadżera, ponieważ jest on mikroframeworkiem, nie tylko menadżerem stanu. Może być użyty samodzielnie, lub w koegzystencji.
Get ma bardzo lekki i prosty menadżer stanu (napisany w tylko 95 lini kodu), który nie używa ChangeNotifier. Sprosta on wymaganiom szczególnie nowych we Flutterze i nie sprawi problemu nawer w dużych aplikacjach.
Get ma bardzo lekki i prosty menadżer stanu (napisany w tylko 95 lini kodu), który nie używa ChangeNotifier. Sprosta on wymaganiom szczególnie nowych we Flutterze i nie sprawi problemu nawet w dużych aplikacjach.
### Reaktywny menadżer stanu
Reaktywne programowanie możee dotrącać niektórych, ponieważ powszechnie jest uważane za skomplikowane. GetX zamienia to w coś prostego:
Reaktywne programowanie może odtrącać niektórych, ponieważ powszechnie jest uważane za skomplikowane. GetX zamienia to w coś prostego:
- Nie musisz tworzyć Strw=eamControllerów,
- Nie musisz tworzyć StreamControllerów,
- Nie musisz tworzyć StreamBuildera dla każdej zmiennej,
- Nie ma potrzeby tworzenia klasy dla kżdego stanu,
- Nie ma potrzeby tworzenia klasy dla każdego stanu,
- Nie musisz tworzyć Get dla inicjalnej zmiennej
Wyobraź sobie, że masz zmienną i za każdym razem jak zmienisz ją chcesz żeby wszystkie widżety używające jej automatycznie się zmieniły
... ... @@ -183,11 +183,11 @@ Obx (() => Text (controller.name));
To wszystko. *Proste*, co nie?
### Bardziej szczegółowo o menadżerze stanu
**Zobacz bardziej szczegółowe wytłumaczenie menadz=żera sranu [tutaj](./documentation/en_US/state_management.md). Znajdują się tam przykłady jak o różnice między prostym menadżerem stanu oraz reaktywnym**
**Zobacz bardziej szczegółowe wytłumaczenie menadżera stanu [tutaj](./documentation/en_US/state_management.md). Znajdują się tam przykłady jak o różnice między prostym menadżerem stanu oraz reaktywnym**
### Video tłumaczące użycie menadżera stanu
Amateur COder nagrał o tym niezwykły film:
Tadas Petra nagrał o tym niezwykły film:
Link: [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw)
... ... @@ -239,42 +239,42 @@ I użyj następujące np.:
```dart
if(data == 'sucess') madeAnything();
```
Zobacz, ze do żadnej z tych operacji nie potrzebowałeś contextu. Jest to jedna z głównych zalet GetX oszczędzającego na niepotrzebnej ogudowie z kod i dającego możliwość uzywania tych metod w klasie kontrolera.
Zobacz, ze do żadnej z tych operacji nie potrzebowałeś contextu. Jest to jedna z głównych zalet GetX oszczędzającego na niepotrzebnej obudowie w kod i dającego możliwość używania tych metod w klasie kontrolera.
### Więcej o routach
**Get używa named routes i także oferuje niskopoziomową obsługę routów! Zobacz bardziej szczegółową dokumentacje [tutaj](./documentation/en_US/route_management.md)**
**Get używa named routes oraz oferuje niskopoziomową obsługę routów! Zobacz bardziej szczegółową dokumentacje [tutaj](./documentation/en_US/route_management.md)**
### Video tłumaczące użycie
Amateur Coder nagrał o tym niezwykły film:
Tadas Petra nagrał o tym niezwykły film:
Link: [Complete GetX Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI)
## Zarządzanie dependencies
Get ma prosty i potężny menadżer dependencies. Pozwala on na otrzymanie tych samych klas jak twoje Bloc lub Kontroler piszac jedną linię kodu bez Provider context i inheritedWidget:
Get ma prosty, a zarazem potężny menadżer dependencies. Pozwala on na otrzymanie tych samych klas jak twoje Bloc lub Kontroler pisząc jedną linię kodu bez Provider context i inheritedWidget:
```dart
Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
```
- Note: Jeśli używasz menadżera stanu Get zwróć uwafę na binding api, które pozwoli Ci łatwiej połączyć twój widok z kontrolerem.
- Note: Jeśli używasz menadżera stanu Get zwróć uwagę na binding api, które pozwoli Ci łatwiej połączyć twój widok z kontrolerem.
https://github.com/jonataslaw/get
**Tip:** Menadżer dependency Get jest oddzielony od innych części pakietu więc jeśli już używasz menadzera stanu(którego kolwiek,bez różnicy) nie musisz przepisywać tego wszystkiego na nowo. Możesz używać tego dodawania dependencies bez poroblemu.
**Tip:** Menadżer dependency Get jest oddzielony od innych części pakietu więc jeśli już używasz menadżera stanu(którego kolwiek, bez różnicy) nie musisz przepisywać tego wszystkiego na nowo. Możesz używać tego dodawania dependencies bez poroblemu.
```dart
controller.fetchApi();
```
Wyobraź sobie, że musisz nawigować pomiędzy wieloma routami i potrzebujesz dane z kontrolerów z poprzednich ekranów. Musiałbyś użyć menadżera stanu z dodatkiem Providera albo Get_it, prawda? Otuż nie z Fet. Muszisz po prostu poprosić Get o znalezienie tego kontrolera i nie potrzebujesz przy tym dodatkowych dependencies.
Wyobraź sobie, że musisz nawigować pomiędzy wieloma routami i potrzebujesz dane z kontrolerów z poprzednich ekranów. Musiałbyś użyć menadżera stanu z dodatkiem Providera albo Get_it, prawda? Otóż nie z Fet. Musisz po prostu poprosić Get o znalezienie tego kontrolera i nie potrzebujesz przy tym dodatkowych 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 controllersfeatury instantiated, Get will always give you the right controller.
//Tak, to wygląda jak Magia, Get znjadzie Twój kontroler i Ci go dostarczy. Możesz mieć nawet MILION kontrolerów, a Get zawsze da Ci prawidłowy kontroler.
```
I wtedy będziesz mógł otrzymać bez problemu z niego dane
I wtedy będziesz mógł otrzymać z niego dane bez żadnego problemu
```dart
Text(controller.textFromApi);
... ... @@ -287,8 +287,8 @@ Text(controller.textFromApi);
Możesz uczestniczyć w rozwoju projektu na różny sposób:
- Pomagając w tłumaczeniu readme na inne języki.
- Dodając dokumentację do readme ( nawet nie połowa funkcji została jeszcze opisana).
- Pisząc artykuły i nagrywając filmy uczące użycia biblioteki Get (będą zamieszczone w readme, a w przyszłości na naszej Wiki).
- Dodając dokumentację do readme (nawet połowa funkcji została jeszcze opisana).
- Pisząc artykuły i nagrywając filmy pokazujące użycie biblioteki Get (będą zamieszczone w readme, a w przyszłości na naszej Wiki).
- Oferując PR-y dla kodu i testów.
- Dodając nowe funkcje.
... ... @@ -298,7 +298,7 @@ Każda współpraca jest mile widziana!
## Zmiana motywu
Nie powinno się uzywać innego widżetu niż GetMaterialApp by go zaktualizować. To może powodować duplikacje kluczy. Wiele osób nawykło do prehistorycznego podejścia tworzenia widżetu "ThemeProvider" tylko po to by zmienić motyw aplikacji. Z Get nie jest to absolutnie wymagane.
Nie powinno się używać innego widżetu niż GetMaterialApp by go zaktualizować. To może powodować duplikacje kluczy. Wiele osób nawykło do prehistorycznego podejścia tworzenia widżetu "ThemeProvider" tylko po to by zmienić motyw aplikacji. Z Get nie jest to wymagane.
Możesz stworzyć customowy motyw i łatwo go dodać z Get.changeTheme bez niepotrzebnego kodu.
... ... @@ -314,7 +314,7 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());featury
Kiedy ciemny motyw jest aktywny zmieni się on na jasny, w przeciwnym wypadku zmieni się na ciemny.
Jeśli interesuje Cię jak zmieniać motywy podąrzaj za samouczkiem na Medium uczącym zmiany motywu z Get:
Jeśli interesuje Cię jak zmieniać motywy podążaj za samouczkiem na Medium pokazującum zmianę motywu przy użyciu Get:
- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Samouczek stworzony przez [Rod Brown](https://github.com/RodBr).
... ... @@ -486,7 +486,7 @@ GetMaterialApp(
## Video tłumaczące inne funkcjonalności GetX
Amateur Coder nagrał niezwykły film tłumaczący powyższe zagadnienia!
Tadas Petra nagrał niezwykły film tłumaczący powyższe zagadnienia!
Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)
... ... @@ -504,7 +504,7 @@ Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)
| NumX | `RxNum` |
| DoubleX | `RxDouble` |
RXController i GetBuilder teraz zostały połączone. Nie musisz już pamiętać którego kontrolerachcesz użyć, po prostu korzystaj z GetxController, będzie działać zarówno dla prostego jak i reaktywnego menadżera stanów.
RXController i GetBuilder teraz zostały połączone. Nie musisz już pamiętać którego kontrolera chcesz użyć, po prostu korzystaj z GetxController, będzie działać zarówno dla prostego jak i reaktywnego menadżera stanów.
2- NamedRoutes
Wcześniej:
... ... @@ -528,7 +528,7 @@ GetMaterialApp(
```
Po co ta zmiana?
Często może być niezbędnym decydowanie która strona będzie wyswietlana w zależności od parametru, lub tokenu logowania. Wczesniejsze podejscie było nieelastyczne nie pozwalając na to. Zawarcie strony w funkcji zmniejszyło sporzycie RAM-u, ze względu na niealokowanie routów od początku działania aplikacji. Pozwoliło to także na takie podejscie:
Często może być niezbędnym decydowanie która strona będzie wyświetlana w zależności od parametru, lub tokenu logowania. Wczesniejsze podejście było nieelastyczne, ponieważ na to nie pozwalało. Zawarcie strony w funkcji zmniejszyło sporzycie RAM-u, ze względu na niealokowanie routów od początku działania aplikacji. Pozwoliło to także na takie podejscie:
```dart
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**Idiomas: [Inglês](README.md), [Indonésia](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinês](README.zh-cn.md), Português Brasileiro (este arquivo), [Espanhol](README-es.md), [Russo](README.ru.md), [Polonês](README.pl.md), [Coreana](README.ko-kr.md).**
**Idiomas: [Inglês](README.md), [Indonésia](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinês](README.zh-cn.md), Português (este arquivo), [Espanhol](README-es.md), [Russo](README.ru.md), [Polonês](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)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
... ... @@ -158,7 +158,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Total de cliques: ${c.count}"))),
// Troque o Navigator.push de 8 linhas por um simples Get.to(). Você não precisa do 'context'
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Ir pra Outra tela"), onPressed: () => Get.to(Outra()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
_Языки: Русский (этот файл), [индонезийский](README.id-ID.md), [урду](README.ur-PK.md), [Английский](README.md), [Китайский](README.zh-cn.md), [Бразильский Португальский](README.pt-br.md), [Испанский](README-es.md), [Польский](README.pl.md), [Kорейский](README.ko-kr.md)._
_Языки: Русский (этот файл), [индонезийский](README.id-ID.md), [урду](README.ur-PK.md), [Английский](README.md), [Китайский](README.zh-cn.md), [Бразильский Португальский](README.pt-br.md), [Испанский](README-es.md), [Польский](README.pl.md), [Kорейский](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)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
... ... @@ -29,14 +29,14 @@ _Языки: Русский (этот файл), [индонезийский](RE
- [Утилиты](#утилиты)
- [Интернационализация](#интернационализация)
- [Переводы](#переводы)
- [Применение переводов](#применение-переводов)
- [Использование переводов](#использование-переводов)
- [Локализация](#локализация)
- [Изменение локализации](#изменение-локализации)
- [Системная локализация](#системная-локализации)
- [Системная локализация](#системная-локализация)
- [Изменение темы](#изменение-темы)
- [Другие API](#другие-api)
- [Дополнительные глобальные настройки и ручные настройки](#дополнительные-глобальные-настройки-и-ручные-настройки)
- [Локальные виджеты состояния](#локальные-виджеты-состояний)
- [Локальные виджеты состояния](#локальные-виджеты-состояния)
- [ValueBuilder](#valuebuilder)
- [ObxValue](#obxvalue)
- [Полезные советы](#полезные-советы)
... ... @@ -45,7 +45,7 @@ _Языки: Русский (этот файл), [индонезийский](RE
- [GetxService](#getxservice)
- [Критические изменения по сравнению с версией 2.0](#критические-изменения-по-сравнению-с-версией-20)
- [Почему Getx?](#почему-getx)
- [Сообщество](#сообщество)
- [Сообщества](#сообщества)
- [Каналы сообщества](#каналы-сообщества)
- [Как внести свой вклад](#как-внести-свой-вклад)
- [Статьи и видео](#статьи-и-видео)
... ... @@ -129,7 +129,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Кликов: ${c.count}"))),
// Замените 8 строк Navigator.push простым Get.to(). Вам не нужен context!
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Перейти к Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ... @@ -811,7 +811,7 @@ class SettingsService extends GetxService {
1- Rx типы:
| До | После |
| До | После |
| ------- | ---------- |
| StringX | `RxString` |
| IntX | `RxInt` |
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
**🌎 اردو ( Selected ✔) [| انگریزی |](README.md) [| انڈونیشی |](README.id-ID.md) [چینی |](README.zh-cn.md) [برازیلی پرتگالی |](README.pt-br.md) [ہسپانوی |](README-es.md) [روسی |](README.ru.md) [پولش |](README.pl.md) [کورین |](README.ko-kr.md)**
**🌎 اردو ( Selected ✔) [| انگریزی |](README.md) [| انڈونیشی |](README.id-ID.md) [چینی |](README.zh-cn.md) [برازیلی پرتگالی |](README.pt-br.md) [ہسپانوی |](README-es.md) [روسی |](README.ru.md) [پولش |](README.pl.md) [کورین |](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)
[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
... ... @@ -42,11 +42,13 @@
- [ترجیح](#ترجیح)
- [ری ڈائریکٹ](#ری-ڈائریکٹ)
- [جب پیج کی درخواست کی جائے](#جب-پیج-کی-درخواست-کی-جائے)
- [آنبائنڈنگ اسٹارٹ](#آنبائنڈنگ-اسٹارٹ)
- [آنپیج بلڈ اسٹارٹ](#آنپیج-بلڈ-اسٹارٹ)
- [جب پیج لوڈ ہو](#جب-پیج-لوڈ-ہو)
- [جب صفحہ تصرف ہوجائے](#جب-صفحہ-تصرف-ہوجائے)
- [دوسرے اعلی درجے کی APIs](#دوسرے-اعلی-درجے-کی-APIs)
- [دوسرے اعلی درجے کی APIs](#دوسرے-اعلی-درجے-کی-apis)
- [اختیاری عالمی ترتیبات اور دستی تشکیلات](#اختیاری-عالمی-ترتیبات-اور-دستی-تشکیلات)
- [مقامی اسٹیٹ ویجٹ](#مقامی-اسٹیٹ-ویجٹ) -
- [مقامی اسٹیٹ ویجٹ](#مقامی-اسٹیٹ-ویجٹ)
- [ویلیو بلڈر](#ویلیو-بلڈر)
- [اوبکس ویلیو](#اوبکس-ویلیو)
- [کارآمد نکات](#کارآمد-نکات)
... ... @@ -54,7 +56,7 @@
- [گیٹ ویجٹ](#گیٹ-ویجٹ)
- [گیٹکس سروس](#گیٹکس-سروس)
- [پچھلے ورژن سے اہم تبدیلیاں](#پچھلے-ورژن-سے-اہم-تبدیلیاں)
- [گیٹکس کیوں؟](#گیٹکس-کیوں؟)
- [گیٹکس کیوں؟](#گیٹکس-کیوں)
- [سماجی خدمات](#سماجی-خدمات)
- [کمیونٹی چینلز](#کمیونٹی-چینلز)
- [کس طرح شراکت کریں](#کس-طرح-شراکت-کریں)
... ... @@ -135,7 +137,7 @@ class Home extends StatelessWidget {
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: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ...
![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
_语言: 中文, [英文](README.md), [印度尼西亚](README.id-ID.md), [乌尔都语](README.ur-PK.md), [巴西葡萄牙语](README.pt-br.md), [俄语](README.ru.md), [西班牙语](README-es.md), [波兰语](README.pl.md), [韩国语](README.ko-kr.md)._
_语言: 中文, [英文](README.md), [印度尼西亚](README.id-ID.md), [乌尔都语](README.ur-PK.md), [巴西葡萄牙语](README.pt-br.md), [俄语](README.ru.md), [西班牙语](README-es.md), [波兰语](README.pl.md), [韩国语](README.ko-kr.md), [法语](README-fr.md), [French](README-fr.md)._
[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
... ... @@ -67,8 +67,13 @@ _霂剛: 銝剜, [(README.md), [摨血側镼蹂(README.id-ID.md), [銋
**此外,通过[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)**
**此外,为了进一步提高您的生产效率,我们还为您准备了一些插件**
- **getx_template**:一键生成每个页面必需的文件夹、文件、模板代码等等
- [Android Studio/Intellij插件](https://plugins.jetbrains.com/plugin/15919-getx)
- **GetX Snippets**:输入少量字母,自动提示选择后,可生成常用的模板代码
- [Android Studio/Intellij扩展](https://plugins.jetbrains.com/plugin/14975-getx-snippets)
- [VSCode扩展](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)
# 安装
... ... @@ -133,7 +138,7 @@ class Home extends StatelessWidget {
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// 用一个简单的Get.to()即可代替Navigator.push那8行,无需上下文!
body: Center(child: RaisedButton(
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
... ... @@ -209,7 +214,7 @@ Obx(() => Text("${controller.name}"));
### 关于状态管理的更多细节
**关于状态管理更深入的解释请查看[这里](./documentation/zh_CN/state_management.md)。在那里你将看到更多的例子,以及简单的阶段管理器和响应式状态管理器之间的区别**
**关于状态管理更深入的解释请查看[这里](./documentation/zh_CN/state_management.md)。在那里你将看到更多的例子,以及简单的状态管理器和响应式状态管理器之间的区别**
你会对GetX的能力有一个很好的了解。
... ... @@ -906,4 +911,6 @@ _銝粹★插賑撠鞊芸撘箄賑
- [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.
- [Flutter GetX use --- simple charm!](https://github.com/CNAD666/getx_template/blob/main/docs/Use%20of%20Flutter%20GetX---simple%20charm!.md) - CNAD666
- [Flutter GetX使用---简洁的魅力!](https://juejin.cn/post/6924104248275763208)
... ...
... ... @@ -20,6 +20,8 @@ linter:
# INCLUDE_FIX (copy of effective dart 1.2.0)
# STYLE
camel_case_types: true
close_sinks: true
unnecessary_statements: true
camel_case_extensions: true
library_names: true
file_names: true
... ... @@ -61,6 +63,7 @@ linter:
avoid_catches_without_on_clauses: true # avoid
avoid_catching_errors: true
use_rethrow_when_possible: true
unrelated_type_equality_checks: true
# DESIGN
use_to_and_as_if_applicable: true # prefer
... ...
... ... @@ -81,9 +81,9 @@ It is possible to lazyLoad a dependency so that it will be instantiated only whe
Get.lazyPut<ApiMock>(() => ApiMock());
Get.lazyPut<FirebaseAuth>(
() => {
// ... some logic if needed
return FirebaseAuth()
() {
// ... some logic if needed
return FirebaseAuth();
},
tag: Math.random().toString(),
fenix: true
... ... @@ -309,7 +309,7 @@ getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<ControllerX>(() => ControllerX());
Get.put<Service>(()=> Api());
}),
... ... @@ -317,7 +317,7 @@ getPages: [
GetPage(
name: '/details',
page: () => DetailsView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<DetailsController>(() => DetailsController());
}),
),
... ...
... ... @@ -246,6 +246,28 @@ print(Get.parameters['user']);
// out: 34954
```
or send multiple parameters like this
```dart
Get.toNamed("/profile/34954?flag=true&country=italy");
```
or
```dart
var parameters = <String, String>{"flag": "true","country": "italy",};
Get.toNamed("/profile/34954", parameters: parameters);
```
On second screen take the data by parameters as usually
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
print(Get.parameters['country']);
// out: 34954 true italy
```
And now, all you need to do is use Get.toNamed() to navigate your named routes, without any context (you can call your routes directly from your BLoC or Controller class), and when your app is compiled to the web, your routes will appear in the url <3
### Middleware
... ... @@ -313,7 +335,7 @@ class First extends StatelessWidget {
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/second");
... ... @@ -338,7 +360,7 @@ class Second extends StatelessWidget {
title: Text('second Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/third");
... ... @@ -357,7 +379,7 @@ class Third extends StatelessWidget {
title: Text("Third Route"),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
onPressed: () {
Get.back();
},
... ... @@ -428,7 +450,7 @@ Get.snackbar(
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// FlatButton mainButton,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
... ... @@ -484,12 +506,12 @@ Get.bottomSheet(
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () => {}
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () => {},
onTap: () {},
),
],
),
... ... @@ -518,7 +540,7 @@ Navigator(
title: Text("Main"),
),
body: Center(
child: FlatButton(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // navigate by your nested route by index
... ...
- [State Management](#state-management)
- [Reactive State Manager](#reactive-state-manager)
* [State Management](#state-management)
+ [Reactive State Manager](#reactive-state-manager)
- [Advantages](#advantages)
- [Maximum performance:](#maximum-performance)
- [Declaring a reactive variable](#declaring-a-reactive-variable)
... ... @@ -11,7 +11,7 @@
- [Why i have to use .value](#why-i-have-to-use-value)
- [Obx()](#obx)
- [Workers](#workers)
- [Simple State Manager](#simple-state-manager)
+ [Simple State Manager](#simple-state-manager)
- [Advantages](#advantages-1)
- [Usage](#usage)
- [How it handles controllers](#how-it-handles-controllers)
... ... @@ -19,30 +19,35 @@
- [Why it exists](#why-it-exists)
- [Other ways of using it](#other-ways-of-using-it)
- [Unique IDs](#unique-ids)
- [Mixing the two state managers](#mixing-the-two-state-managers)
- [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)
+ [Mixing the two state managers](#mixing-the-two-state-managers)
+ [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)
# State Management
GetX does not use Streams or ChangeNotifier like other state managers. Why? In addition to building applications for android, iOS, web, linux, macos and linux, with GetX you can build server applications with the same syntax as Flutter/GetX. In order to improve response time and reduce RAM consumption, we created GetValue and GetStream, which are low latency solutions that deliver a lot of performance, at a low operating cost. We use this base to build all of our resources, including state management.
- _Complexity_: Some state managers are complex and have a lot of boilerplate. With GetX you don't have to define a class for each event, the code is highly clean and clear, and you do a lot more by writing less. Many people have given up on Flutter because of this topic, and they now finally have a stupidly simple solution for managing states.
- _No code generators_: You spend half your development time writing your application logic. Some state managers rely on code generators to have minimally readable code. Changing a variable and having to run build_runner can be unproductive, and often the waiting time after a flutter clean will be long, and you will have to drink a lot of coffee.
* _Complexity_: Some state managers are complex and have a lot of boilerplate. With GetX you don't have to define a class for each event, the code is highly clean and clear, and you do a lot more by writing less. Many people have given up on Flutter because of this topic, and they now finally have a stupidly simple solution for managing states.
* _No code generators_: You spend half your development time writing your application logic. Some state managers rely on code generators to have minimally readable code. Changing a variable and having to run build_runner can be unproductive, and often the waiting time after a flutter clean will be long, and you will have to drink a lot of coffee.
With GetX everything is reactive, and nothing depends on code generators, increasing your productivity in all aspects of your development.
- _It does not depend on context_: You probably already needed to send the context of your view to a controller, making the View's coupling with your business logic high. You have probably had to use a dependency for a place that has no context, and had to pass the context through various classes and functions. This just doesn't exist with GetX. You have access to your controllers from within your controllers without any context. You don't need to send the context by parameter for literally nothing.
- _Granular control_: most state managers are based on ChangeNotifier. ChangeNotifier will notify all widgets that depend on it when notifyListeners is called. If you have 40 widgets on one screen, which have a variable of your ChangeNotifier class, when you update one, all of them will be rebuilt.
* _It does not depend on context_: You probably already needed to send the context of your view to a controller, making the View's coupling with your business logic high. You have probably had to use a dependency for a place that has no context, and had to pass the context through various classes and functions. This just doesn't exist with GetX. You have access to your controllers from within your controllers without any context. You don't need to send the context by parameter for literally nothing.
* _Granular control_: most state managers are based on ChangeNotifier. ChangeNotifier will notify all widgets that depend on it when notifyListeners is called. If you have 40 widgets on one screen, which have a variable of your ChangeNotifier class, when you update one, all of them will be rebuilt.
With GetX, even nested widgets are respected. If you have Obx watching your ListView, and another watching a checkbox inside the ListView, when changing the CheckBox value, only it will be updated, when changing the List value, only the ListView will be updated.
- _It only reconstructs if its variable REALLY changes_: GetX has flow control, that means if you display a Text with 'Paola', if you change the observable variable to 'Paola' again, the widget will not be reconstructed. That's because GetX knows that 'Paola' is already being displayed in Text, and will not do unnecessary reconstructions.
* _It only reconstructs if its variable REALLY changes_: GetX has flow control, that means if you display a Text with 'Paola', if you change the observable variable to 'Paola' again, the widget will not be reconstructed. That's because GetX knows that 'Paola' is already being displayed in Text, and will not do unnecessary reconstructions.
Most (if not all) current state managers will rebuild on the screen.
## 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 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.
Reactive programming with Get is as easy as using setState.
... ... @@ -50,13 +55,13 @@ Let's imagine that you have a name variable and want that every time you change
This is your count variable:
```dart
``` dart
var name = 'Jonatas Borges';
```
To make it observable, you just need to add ".obs" to the end of it:
```dart
``` dart
var name = 'Jonatas Borges'.obs;
```
... ... @@ -64,34 +69,34 @@ That's all. It's *that* simple.
From now on, we might refer to this reactive-".obs"(ervables) variables as _Rx_.
What did we do under the hood? We created a `Stream` of `String`s, assigned the initial value `"Jonatas Borges"`, we notified all widgets that use `"Jonatas Borges"` that they now "belong" to this variable, and when the _Rx_ value changes, they will have to change as well.
What did we do under the hood? We created a `Stream` of `String` s, assigned the initial value `"Jonatas Borges"` , we notified all widgets that use `"Jonatas Borges"` that they now "belong" to this variable, and when the _Rx_ value changes, they will have to change as well.
This is the **magic of GetX**, thanks to Dart's capabilities.
But, as we know, a `Widget` can only be changed if it is inside a function, because static classes do not have the power to "auto-change".
You will need to create a `StreamBuilder`, subscribe to this variable to listen for changes, and create a "cascade" of nested `StreamBuilder` if you want to change several variables in the same scope, right?
You will need to create a `StreamBuilder` , subscribe to this variable to listen for changes, and create a "cascade" of nested `StreamBuilder` if you want to change several variables in the same scope, right?
No, you don't need a `StreamBuilder`, but you are right about static classes.
No, you don't need a `StreamBuilder` , but you are right about static classes.
Well, in the view, we usually have a lot of boilerplate when we want to change a specific Widget, that's the Flutter way.
With **GetX** you can also forget about this boilerplate code.
`StreamBuilder( … )`? `initialValue: …`? `builder: …`? Nope, you just need to place this variable inside an `Obx()` Widget.
`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Nope, you just need to place this variable inside an `Obx()` Widget.
```dart
``` dart
Obx (() => Text (controller.name));
```
_What do you need to memorize?_ Only `Obx(() =>`.
_What do you need to memorize?_ Only `Obx(() =>` .
You are just passing that Widget through an arrow-function into an `Obx()` (the "Observer" of the _Rx_).
`Obx` is pretty smart, and will only change if the value of `controller.name` changes.
If `name` is `"John"`, and you change it to `"John"` (`name.value = "John"`), as it's the same `value` as before, nothing will change on the screen, and `Obx`, to save resources, will simply ignore the new value and not rebuild the Widget. **Isn't that amazing?**
If `name` is `"John"` , and you change it to `"John"` ( `name.value = "John"` ), as it's the same `value` as before, nothing will change on the screen, and `Obx` , to save resources, will simply ignore the new value and not rebuild the Widget. **Isn't that amazing?**
> So, what if I have 5 _Rx_ (observable) variables within an `Obx`?
> So, what if I have 5 _Rx_ (observable) variables within an `Obx` ?
It will just update when **any** of them changes.
... ... @@ -101,29 +106,32 @@ Nope, just the **specific Widget** that uses that _Rx_ variable.
So, **GetX** only updates the screen, when the _Rx_ variable changes it's value.
```
```
final isOpen = false.obs;
// NOTHING will happen... same value.
void onButtonTap() => isOpen.value=false;
```
### Advantages
**GetX()** helps you when you need **granular** control over what's being updated.
If you do not need `unique IDs`, because all your variables will be modified when you perform an action, then use `GetBuilder`,
because it's a Simple State Updater (in blocks, like `setState()`), made in just a few lines of code.
If you do not need `unique IDs` , because all your variables will be modified when you perform an action, then use `GetBuilder` ,
because it's a Simple State Updater (in blocks, like `setState()` ), made in just a few lines of code.
It was made simple, to have the least CPU impact, and just to fulfill a single purpose (a _State_ rebuild) and spend the minimum resources possible.
If you need a **powerful** State Manager, you can't go wrong with **GetX**.
It doesn't work with variables, but __flows__, everything in it are `Streams` under the hood.
You can use _rxDart_ in conjunction with it, because everything are `Streams`,
you can listen the `event` of each "_Rx_ variable",
you can listen to the `event` of each "_Rx_ variable",
because everything in it are `Streams`.
It is literally a _BLoC_ approach, easier than _MobX_, and without code generators or decorations.
You can turn **anything** into an _"Observable"_ with just a `.obs`.
You can turn **anything** into an _"Observable"_ with just a `.obs` .
### Maximum performance:
... ... @@ -134,19 +142,18 @@ If you experience any errors in your app, and send a duplicate change of State,
**GetX** will ensure it will not crash.
With **GetX** the State only changes if the `value` change.
That's the main difference between **GetX**, and using _`computed` from MobX_.
That's the main difference between **GetX**, and using _ `computed` from MobX_.
When joining two __observables__, and one changes; the listener of that _observable_ will change as well.
With **GetX**, if you join two variables, `GetX()` (similar to `Observer()`) will only rebuild if it implies a real change of State.
With **GetX**, if you join two variables, `GetX()` (similar to `Observer()` ) will only rebuild if it implies a real change of State.
### Declaring a reactive variable
You have 3 ways to turn a variable into an "observable".
1 - The first is using **`Rx{Type}`**.
```dart
``` dart
// initial value is recommended, but not mandatory
final name = RxString('');
final isLogged = RxBool(false);
... ... @@ -158,7 +165,7 @@ final myMap = RxMap<String, int>({});
2 - The second is to use **`Rx`** and use Darts Generics, `Rx<Type>`
```dart
``` dart
final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
... ... @@ -171,9 +178,9 @@ final myMap = Rx<Map<String, int>>({});
final user = Rx<User>();
```
3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value`:
3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value` :
```dart
``` dart
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
... ... @@ -193,20 +200,19 @@ To be prepared, from now on, you should always start your _Rx_ variables with an
> Transforming a variable into an _observable_ + _initial value_ with **GetX** is the simplest, and most practical approach.
You will literally add a "`.obs`" to the end of your variable, and **that’s it**, you’ve made it observable,
and its `.value`, well, will be the _initial value_).
You will literally add a " `.obs` " to the end of your variable, and **that’s it**, you’ve made it observable,
and its `.value` , well, will be the _initial value_).
### Using the values in the view
```dart
``` dart
// controller file
final count1 = 0.obs;
final count2 = 0.obs;
int get sum => count1.value + count2.value;
```
```dart
``` dart
// view file
GetX<Controller>(
builder: (controller) {
... ... @@ -228,30 +234,35 @@ GetX<Controller>(
),
```
If we increment `count1.value++`, it will print:
- `count 1 rebuild`
- `count 3 rebuild`
If we increment `count1.value++` , it will print:
* `count 1 rebuild`
because `count1` has a value of `1`, and `1 + 0 = 1`, changing the `sum` getter value.
* `count 3 rebuild`
If we change `count2.value++`, it will print:
- `count 2 rebuild`
- `count 3 rebuild`
because `count1` has a value of `1` , and `1 + 0 = 1` , changing the `sum` getter value.
because `count2.value` changed, and the result of the `sum` is now `2`.
If we change `count2.value++` , it will print:
* `count 2 rebuild`
* `count 3 rebuild`
because `count2.value` changed, and the result of the `sum` is now `2` .
* NOTE: By default, the very first event will rebuild the widget, even if it is the same `value`.
- NOTE: By default, the very first event will rebuild the widget, even if it is the same `value`.
This behavior exists due to Boolean variables.
Imagine you did this:
```dart
``` dart
var isLogged = false.obs;
```
And then, you checked if a user is "logged in" to trigger an event in `ever`.
And then, you checked if a user is "logged in" to trigger an event in `ever` .
```dart
``` dart
@override
onInit(){
ever(isLogged, fireRoute);
... ... @@ -267,18 +278,18 @@ fireRoute(logged) {
}
```
if `hasToken` was `false`, there would be no change to `isLogged`, so `ever()` would never be called.
if `hasToken` was `false` , there would be no change to `isLogged` , so `ever()` would never be called.
To avoid this type of behavior, the first change to an _observable_ will always trigger an event,
even if it contains the same `.value`.
even if it contains the same `.value` .
You can remove this behavior if you want, using:
`isLogged.firstRebuild = false;`
`isLogged.firstRebuild = false;`
### Conditions to rebuild
In addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition.
```dart
``` dart
// First parameter: condition, must return true or false.
// Second parameter: the new value to apply if the condition is true.
list.addIf(item < limit, item);
... ... @@ -288,7 +299,7 @@ Without decorations, without a code generator, without complications :smile:
Do you know Flutter's counter app? Your Controller class might look like this:
```dart
``` dart
class CountController extends GetxController {
final count = 0.obs;
}
... ... @@ -296,7 +307,7 @@ class CountController extends GetxController {
With a simple:
```dart
``` dart
controller.count.value++
```
... ... @@ -307,7 +318,8 @@ You could update the counter variable in your UI, regardless of where it is stor
You can transform anything on obs. Here are two ways of doing it:
* You can convert your class values to obs
```dart
``` dart
class RxUser {
final name = "Camila".obs;
final age = 18.obs;
... ... @@ -315,7 +327,8 @@ class RxUser {
```
* or you can convert the entire class to be an observable
```dart
``` dart
class User {
User({String name, int age});
var name;
... ... @@ -333,7 +346,7 @@ Lists are completely observable as are the objects within it. That way, if you a
You also don't need to use ".value" with lists, the amazing dart api allowed us to remove that.
Unfortunaly primitive types like String and int cannot be extended, making the use of .value mandatory, but that won't be a problem if you work with gets and setters for these.
```dart
``` dart
// On the controller
final String title = 'User Info:'.obs
final list = List<User>().obs;
... ... @@ -347,7 +360,7 @@ ListView.builder (
When you are making your own classes observable, there is a different way to update them:
```dart
``` dart
// on the model file
// we are going to make the entire class observable instead of each attribute
class User() {
... ... @@ -356,7 +369,6 @@ class User() {
int age;
}
// on the controller file
final user = User().obs;
// when you need to update the user variable:
... ... @@ -385,7 +397,7 @@ You can literally add 3 letters to your pubspec (get) and a colon and start prog
The total weight of this library is less than that of a single state manager, even though it is a complete solution, and that is what you must understand.
If you are bothered by `.value`, and like a code generator, MobX is a great alternative, and you can use it in conjunction with Get. For those who want to add a single dependency in pubspec and start programming without worrying about the version of a package being incompatible with another, or if the error of a state update is coming from the state manager or dependency, or still, do not want to worrying about the availability of controllers, whether literally "just programming", get is just perfect.
If you are bothered by `.value` , and like a code generator, MobX is a great alternative, and you can use it in conjunction with Get. For those who want to add a single dependency in pubspec and start programming without worrying about the version of a package being incompatible with another, or if the error of a state update is coming from the state manager or dependency, or still, do not want to worrying about the availability of controllers, whether literally "just programming", get is just perfect.
If you have no problem with the MobX code generator, or have no problem with the BLoC boilerplate, you can simply use Get for routes, and forget that it has state manager. Get SEM and RSM were born out of necessity, my company had a project with more than 90 controllers, and the code generator simply took more than 30 minutes to complete its tasks after a Flutter Clean on a reasonably good machine, if your project it has 5, 10, 15 controllers, any state manager will supply you well. If you have an absurdly large project, and code generator is a problem for you, you have been awarded this solution.
... ... @@ -400,7 +412,7 @@ Obviously, if you don't use a type, you will need to have an instance of your co
Workers will assist you, triggering specific callbacks when an event occurs.
```dart
``` dart
/// Called every time `count1` changes.
ever(count1, (_) => print("$_ has been changed"));
... ... @@ -413,28 +425,34 @@ debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));
/// Ignore all changes within 1 second.
interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));
```
All workers (except `debounce`) have a `condition` named parameter, which can be a `bool` or a callback that returns a `bool`.
All workers (except `debounce` ) have a `condition` named parameter, which can be a `bool` or a callback that returns a `bool` .
This `condition` defines when the `callback` function executes.
All workers returns a `Worker` instance, that you can use to cancel ( via `dispose()` ) the worker.
- **`ever`**
* **`ever`**
is called every time the _Rx_ variable emits a new value.
- **`everAll`**
Much like `ever`, but it takes a `List` of _Rx_ values Called every time its variable is changed. That's it.
* **`everAll`**
Much like `ever` , but it takes a `List` of _Rx_ values Called every time its variable is changed. That's it.
* **`once`**
- **`once`**
'once' is called only the first time the variable has been changed.
- **`debounce`**
* **`debounce`**
'debounce' is very useful in search functions, where you only want the API to be called when the user finishes typing. If the user types "Jonny", you will have 5 searches in the APIs, by the letter J, o, n, n, and y. With Get this does not happen, because you will have a "debounce" Worker that will only be triggered at the end of typing.
- **`interval`**
* **`interval`**
'interval' is different from the debouce. debouce if the user makes 1000 changes to a variable within 1 second, he will send only the last one after the stipulated timer (the default is 800 milliseconds). Interval will instead ignore all user actions for the stipulated period. If you send events for 1 minute, 1000 per second, debounce will only send you the last one, when the user stops strafing events. interval will deliver events every second, and if set to 3 seconds, it will deliver 20 events that minute. This is recommended to avoid abuse, in functions where the user can quickly click on something and get some advantage (imagine that the user can earn coins by clicking on something, if he clicked 300 times in the same minute, he would have 300 coins, using interval, you you can set a time frame for 3 seconds, and even then clicking 300 or a thousand times, the maximum he would get in 1 minute would be 20 coins, clicking 300 or 1 million times). The debounce is suitable for anti-DDos, for functions like search where each change to onChange would cause a query to your api. Debounce will wait for the user to stop typing the name, to make the request. If it were used in the coin scenario mentioned above, the user would only win 1 coin, because it is only executed, when the user "pauses" for the established time.
- NOTE: Workers should always be used when starting a Controller or Class, so it should always be on onInit (recommended), Class constructor, or the initState of a StatefulWidget (this practice is not recommended in most cases, but it shouldn't have any side effects).
* NOTE: Workers should always be used when starting a Controller or Class, so it should always be on onInit (recommended), Class constructor, or the initState of a StatefulWidget (this practice is not recommended in most cases, but it shouldn't have any side effects).
## Simple State Manager
... ... @@ -466,7 +484,7 @@ That way, if you want an individual controller, you can assign IDs for that, or
### Usage
```dart
``` dart
// Create controller class and extends GetxController
class Controller extends GetxController {
int counter = 0;
... ... @@ -487,13 +505,13 @@ GetBuilder<Controller>(
**Done!**
- You have already learned how to manage states with Get.
* You have already learned how to manage states with Get.
- Note: You may want a larger organization, and not use the init property. For that, you can create a class and extends Bindings class, and within it mention the controllers that will be created within that route. Controllers will not be created at that time, on the contrary, this is just a statement, so that the first time you use a Controller, Get will know where to look. Get will remain lazyLoad, and will continue to dispose Controllers when they are no longer needed. See the pub.dev example to see how it works.
* Note: You may want a larger organization, and not use the init property. For that, you can create a class and extends Bindings class, and within it mention the controllers that will be created within that route. Controllers will not be created at that time, on the contrary, this is just a statement, so that the first time you use a Controller, Get will know where to look. Get will remain lazyLoad, and will continue to dispose Controllers when they are no longer needed. See the pub.dev example to see how it works.
If you navigate many routes and need data that was in your previously used controller, you just need to use GetBuilder Again (with no init):
```dart
``` dart
class OtherClass extends StatelessWidget {
@override
Widget build(BuildContext context) {
... ... @@ -508,9 +526,9 @@ class OtherClass extends StatelessWidget {
```
If you need to use your controller in many other places, and outside of GetBuilder, just create a get in your controller and have it easily. (or use `Get.find<Controller>()`)
If you need to use your controller in many other places, and outside of GetBuilder, just create a get in your controller and have it easily. (or use `Get.find<Controller>()` )
```dart
``` dart
class Controller extends GetxController {
/// You do not need that. I recommend using it just for ease of syntax.
... ... @@ -529,7 +547,7 @@ class Controller extends GetxController {
And then you can access your controller directly, that way:
```dart
``` dart
FloatingActionButton(
onPressed: () {
Controller.to.increment(),
... ... @@ -544,7 +562,7 @@ When you press FloatingActionButton, all widgets that are listening to the 'coun
Let's say we have this:
`Class a => Class B (has controller X) => Class C (has controller X)`
`Class a => Class B (has controller X) => Class C (has controller X)`
In class A the controller is not yet in memory, because you have not used it yet (Get is lazyLoad). In class B you used the controller, and it entered memory. In class C you used the same controller as in class B, Get will share the state of controller B with controller C, and the same controller is still in memory. If you close screen C and screen B, Get will automatically take controller X out of memory and free up resources, because Class a is not using the controller. If you navigate to B again, controller X will enter memory again, if instead of going to class C, you return to class A again, Get will take the controller out of memory in the same way. If class C didn't use the controller, and you took class B out of memory, no class would be using controller X and likewise it would be disposed of. The only exception that can mess with Get, is if you remove B from the route unexpectedly, and try to use the controller in C. In this case, the creator ID of the controller that was in B was deleted, and Get was programmed to remove it from memory every controller that has no creator ID. If you intend to do this, add the "autoRemove: false" flag to class B's GetBuilder and use adoptID = true; in class C's GetBuilder.
... ... @@ -557,7 +575,7 @@ Unless you need to use a mixin, like TickerProviderStateMixin, it will be totall
You can call all methods of a StatefulWidget directly from a GetBuilder.
If you need to call initState() or dispose() method for example, you can call them directly;
```dart
``` dart
GetBuilder<Controller>(
initState: (_) => Controller.to.fetchApi(),
dispose: (_) => Controller.to.closeStreams(),
... ... @@ -567,7 +585,7 @@ GetBuilder<Controller>(
A much better approach than this is to use the onInit() and onClose() method directly from your controller.
```dart
``` dart
@override
void onInit() {
fetchApi();
... ... @@ -575,7 +593,7 @@ void onInit() {
}
```
- NOTE: If you want to start a method at the moment the controller is called for the first time, you DON'T NEED to use constructors for this, in fact, using a performance-oriented package like Get, this borders on bad practice, because it deviates from the logic in which the controllers are created or allocated (if you create an instance of this controller, the constructor will be called immediately, you will be populating a controller before it is even used, you are allocating memory without it being in use, this definitely hurts the principles of this library). The onInit() methods; and onClose(); were created for this, they will be called when the Controller is created, or used for the first time, depending on whether you are using Get.lazyPut or not. If you want, for example, to make a call to your API to populate data, you can forget about the old-fashioned method of initState/dispose, just start your call to the api in onInit, and if you need to execute any command like closing streams, use the onClose() for that.
* NOTE: If you want to start a method at the moment the controller is called for the first time, you DON'T NEED to use constructors for this, in fact, using a performance-oriented package like Get, this borders on bad practice, because it deviates from the logic in which the controllers are created or allocated (if you create an instance of this controller, the constructor will be called immediately, you will be populating a controller before it is even used, you are allocating memory without it being in use, this definitely hurts the principles of this library). The onInit() methods; and onClose(); were created for this, they will be called when the Controller is created, or used for the first time, depending on whether you are using Get.lazyPut or not. If you want, for example, to make a call to your API to populate data, you can forget about the old-fashioned method of initState/dispose, just start your call to the api in onInit, and if you need to execute any command like closing streams, use the onClose() for that.
### Why it exists
... ... @@ -587,7 +605,7 @@ You do not need to call the device, you have the onClose() method that will be c
Do not call a dispose method inside GetxController, it will not do anything, remember that the controller is not a Widget, you should not "dispose" it, and it will be automatically and intelligently removed from memory by Get. If you used any stream on it and want to close it, just insert it into the close method. Example:
```dart
``` dart
class Controller extends GetxController {
StreamController<User> user = StreamController<User>();
StreamController<String> name = StreamController<String>();
... ... @@ -604,15 +622,15 @@ class Controller extends GetxController {
Controller life cycle:
- onInit() where it is created.
- onClose() where it is closed to make any changes in preparation for the delete method
- deleted: you do not have access to this API because it is literally removing the controller from memory. It is literally deleted, without leaving any trace.
* onInit() where it is created.
* onClose() where it is closed to make any changes in preparation for the delete method
* deleted: you do not have access to this API because it is literally removing the controller from memory. It is literally deleted, without leaving any trace.
### Other ways of using it
You can use Controller instance directly on GetBuilder value:
```dart
``` dart
GetBuilder<Controller>(
init: Controller(),
builder: (value) => Text(
... ... @@ -623,7 +641,7 @@ GetBuilder<Controller>(
You may also need an instance of your controller outside of your GetBuilder, and you can use these approaches to achieve this:
```dart
``` dart
class Controller extends GetxController {
static Controller get to => Get.find();
[...]
... ... @@ -639,7 +657,7 @@ GetBuilder<Controller>(
or
```dart
``` dart
class Controller extends GetxController {
// static Controller get to => Get.find(); // with no static get
[...]
... ... @@ -653,9 +671,9 @@ GetBuilder<Controller>(
),
```
- You can use "non-canonical" approaches to do this. If you are using some other dependency manager, like get_it, modular, etc., and just want to deliver the controller instance, you can do this:
* You can use "non-canonical" approaches to do this. If you are using some other dependency manager, like get_it, modular, etc., and just want to deliver the controller instance, you can do this:
```dart
``` dart
Controller controller = Controller();
[...]
GetBuilder<Controller>(
... ... @@ -671,7 +689,7 @@ GetBuilder<Controller>(
If you want to refine a widget's update control with GetBuilder, you can assign them unique IDs:
```dart
``` dart
GetBuilder<Controller>(
id: 'text'
init: Controller(), // use it only first time on each controller
... ... @@ -683,13 +701,13 @@ GetBuilder<Controller>(
And update it this form:
```dart
``` dart
update(['text']);
```
You can also impose conditions for the update:
```dart
``` dart
update(['text'], counter < 10);
```
... ... @@ -701,6 +719,55 @@ Some people opened a feature request, as they wanted to use only one type of rea
Extending GetxController is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods. You can use any class for this, but I strongly recommend you use the GetxController class to place your variables, whether they are observable or not.
## 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),
),
);
}
```
## GetBuilder vs GetX vs Obx vs MixinBuilder
... ...
... ... @@ -242,7 +242,21 @@ Y en la segunda pantalla tome los datos por parámetro
```dart
print(Get.parameters['user']);
// out: 34954
// salida: 34954
```
o envie multiples parametros de la siguiente manera
```dart
Get.toNamed("/profile/34954?flag=true");
```
En la segunda pantalla tome los parametros como lo haria normalmente
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
// salida: 34954 true
```
Y ahora, todo lo que necesita hacer es usar Get.toNamed() para navegar por sus rutas nombradas, sin ningún contexto (puede llamar a sus rutas directamente desde su clase BLoC o Controller), y cuando su aplicación se compila para web, sus rutas aparecerán en la url del navegador <3
... ... @@ -312,7 +326,7 @@ class First extends StatelessWidget {
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/second");
... ... @@ -337,7 +351,7 @@ class Second extends StatelessWidget {
title: Text('second Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/third");
... ... @@ -356,7 +370,7 @@ class Third extends StatelessWidget {
title: Text("Third Route"),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
onPressed: () {
Get.back();
},
... ... @@ -427,7 +441,7 @@ Get.snackbar(
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// FlatButton mainButton,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
... ... @@ -484,12 +498,12 @@ Get.bottomSheet(
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () => {}
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () => {},
onTap: () {},
),
],
),
... ... @@ -519,7 +533,7 @@ Navigator(
title: Text("Main"),
),
body: Center(
child: FlatButton(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // navigate by your nested route by index
... ...
# Gestion des dépendances
- [Gestion des dépendances](#Gestion-des-dépendances)
- [Instanciation des methodes](#Instanciation-des-methodes)
- [Get.put()](#getput)
- [Get.lazyPut](#getlazyput)
- [Get.putAsync](#getputasync)
- [Get.create](#getcreate)
- [Utilisation de méthodes/classes instanciées](#utilisation-de-mthodes-classes-instancies)
- [Différences entre les méthodes](#differences-entre-les-methodes)
- [Bindings](#bindings)
- [Classe Bindings](#classe-bindings)
- [BindingsBuilder](#bindingsbuilder)
- [SmartManagement](#smartmanagement)
- [Comment changer](#comment-changer)
- [SmartManagement.full](#smartmanagementfull)
- [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)
- [SmartManagement.keepFactory](#smartmanagementkeepfactory)
- [Comment Bindings fonctionne sous le capot](#comment-bindings-fonctionne-sous-le-capot)
- [Notes](#notes)
Get a un gestionnaire de dépendances simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou Controller avec une seule ligne de code, pas de context Provider, pas d' inheritedWidget:
```dart
Controller controller = Get.put(Controller()); // Au lieu de Controller controller = Controller();
```
Au lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get, qui la rendra disponible dans toute votre application.
Vous pouvez donc utiliser votre contrôleur (ou classe Bloc) normalement
- Note: Si vous utilisez le gestionnaire d'état de Get, faites plus attention à l'API [Bindings] (# bindings), qui facilitera la connexion de votre vue à votre contrôleur.
- Note²: La gestion des dépendances est découplée des autres parties du package, donc si, par exemple, votre application utilise déjà un gestionnaire d'état (n'importe lequel, peu importe), vous n'avez pas besoin de changer cela, vous pouvez utiliser ce manager d'injection de dépendance sans aucun problème.
## Instanciation des methodes
Les méthodes et leurs paramètres configurables sont:
### Get.put()
La manière la plus courante d'insérer une dépendance. Bon pour les contrôleurs de vos vues par exemple.
```dart
Get.put<SomeClass>(SomeClass());
Get.put<LoginController>(LoginController(), permanent: true);
Get.put<ListItemController>(ListItemController, tag: "un String unique");
```
Ce sont toutes les options que vous pouvez définir lorsque vous utilisez put:
```dart
Get.put<S>(
// obligatoire: la classe que vous voulez que get enregistre, comme un 'controler' ou autre
// note: "S" signifie que ca peut etre une classe de n'importe quel type
S dependency
// optionnel: c'est pour quand vous voulez plusieurs classes qui sont du même type
// puisque vous obtenez normalement une classe en utilisant Get.find<Controller>(),
// vous devez utiliser ce tag pour indiquer de quelle instance vous avez besoin
// doit être un String unique
String tag,
// optionnel: par défaut, get supprimera les instances une fois qu'elles ne seront plus utilisées (exemple,
// le contrôleur d'une vue qui est fermée), mais vous pourriez avoir besoin que l'instance
// soit conservée dans toute l'application, comme une instance de sharedPreferences ou quelque chose du genre
// donc vous utilisez ceci
// équivaut à false par défaut
bool permanent = false,
// facultatif: permet après avoir utilisé une classe abstraite dans un test, de la remplacer par une autre et de suivre le test.
// équivaut à false par défaut
bool overrideAbstract = false,
// facultatif: vous permet de créer la dépendance en utilisant la fonction au lieu de la dépendance elle-même.
// ce n'est pas couramment utilisé
InstanceBuilderCallback<S> builder,
)
```
### Get.lazyPut
Il est possible de lazyLoad une dépendance afin qu'elle ne soit instanciée que lorsqu'elle est utilisée. Très utile pour les classes qui demandent beaucoup de ressources ou si vous souhaitez instancier plusieurs classes en un seul endroit (comme dans une classe Bindings) et que vous savez que vous n'utiliserez pas cette classe à ce moment-là.
```dart
/// ApiMock ne sera appelé que lorsque quelqu'un utilise Get.find <ApiMock> pour la première fois
Get.lazyPut<ApiMock>(() => ApiMock());
Get.lazyPut<FirebaseAuth>(
() {
// ... some logic if needed
return FirebaseAuth();
},
tag: Math.random().toString(),
fenix: true
)
Get.lazyPut<Controller>(() => Controller() )
```
Ce sont toutes les options que vous pouvez définir lors de l'utilisation de lazyPut:
```dart
Get.lazyPut<S>(
// obligatoire: une méthode qui sera exécutée lorsque votre classe sera appelée pour la première fois
InstanceBuilderCallback builder,
// facultatif: identique à Get.put(), il est utilisé lorsque vous voulez plusieurs instances différentes d'une même classe
// doit être unique
String tag,
// facultatif: cela est similaire à "permanent", la différence est que l'instance est supprimée lorsqu'elle
// n'est pas utilisée, mais lorsqu'elle est à nouveau nécessaire, Get recrée l'instance
// identique à "SmartManagement.keepFactory" dans l'API Bindings
// vaut false par défaut
bool fenix = false
)
```
### Get.putAsync
Si vous souhaitez enregistrer une instance async, vous pouvez utiliser `Get.putAsync`:
```dart
Get.putAsync<SharedPreferences>(() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', 12345);
return prefs;
});
Get.putAsync<YourAsyncClass>(() async => await YourAsyncClass())
```
Ce sont toutes les options que vous pouvez définir lors de l'utilisation de putAsync:
```dart
Get.putAsync<S>(
// obligatoire: une méthode async qui sera exécutée pour instancier votre classe
AsyncInstanceBuilderCallback<S> builder,
// facultatif: identique à Get.put(), il est utilisé lorsque vous voulez plusieurs instances différentes d'une même classe
// doit être unique
String tag,
// facultatif: identique à Get.put(), utilisé lorsque vous devez maintenir cette instance active dans l'ensemble de l'application
// vaut false par défaut
bool permanent = false
)
```
### Get.create
Celui-ci est délicat. Une explication détaillée de ce que c'est et des différences d'avec les autres peut être trouvée dans la section [Différences entre les méthodes:](#differences-entre-les-methodes).
```dart
Get.Create<SomeClass>(() => SomeClass());
Get.Create<LoginController>(() => LoginController());
```
Ce sont toutes les options que vous pouvez définir lors de l'utilisation de create:
```dart
Get.create<S>(
// requis: une fonction qui renvoie une classe qui sera "fabriquée" chaque
// fois que `Get.find()` est appelé
// Exemple: Get.create<YourClass>(() => YourClass())
FcBuilderFunc<S> builder,
// facultatif: comme Get.put(), mais il est utilisé lorsque vous avez besoin de plusieurs instances
// d'une même classe
// Utile dans le cas où vous avez une liste oú chaque élément a besoin de son propre contrôleur
// doit être une String unique. Changez simplement de 'tag' en 'name'
String name,
// optionnel: tout comme dans `Get.put()`, c'est pour quand vous devez garder l'
// instance vivante dans toute l'application. La différence est que dans Get.create,
// permanent est 'true' par défaut
bool permanent = true
```
## Utilisation de méthodes/classes instanciées
Imaginez que vous ayez parcouru de nombreuses routes et que vous ayez besoin d'une donnée qui a été laissée 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 "find" (trouver) votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires:
```dart
final controller = Get.find<Controller>();
// OR
Controller controller = Get.find();
// Oui, cela ressemble à Magic, Get trouvera votre contrôleur et vous le livrera.
// Vous pouvez avoir 1 million de contrôleurs instanciés, Get vous trouvera toujours le bon contrôleur.
```
Et puis vous pourrez récupérer les données de votre contrôleur qui ont été obtenues là-bas:
```dart
Text(controller.textFromApi);
```
La valeur renvoyée étant une classe normale, vous pouvez faire tout ce que vous voulez:
```dart
int count = Get.find<SharedPreferences>().getInt('counter');
print(count); // donne: 12345
```
Pour supprimer une instance de Get:
```dart
Get.delete<Controller>(); //généralement, vous n'avez pas besoin de le faire car GetX supprime déjà les contrôleurs inutilisés-
```
## Differences entre les methodes
Commençons par le `fenix` de Get.lazyPut et le `permanent` des autres méthodes.
La différence fondamentale entre `permanent` et `fenix` réside dans la manière dont vous souhaitez stocker vos instances.
Renforcement: par défaut, GetX supprime les instances lorsqu'elles ne sont pas utilisées.
Cela signifie que: Si l'écran 1 a le contrôleur 1 et l'écran 2 a le contrôleur 2 et que vous supprimez la première route du Stack, (comme si vous utilisez `Get.off()` ou `Get.offNamed()`) le contrôleur 1 a perdu son utilisation, il sera donc effacé.
Mais si vous optez pour l'utilisation de `permanent: true`, alors le contrôleur ne sera pas perdu dans cette transition - ce qui est très utile pour les services que vous souhaitez maintenir actif dans toute l'application.
`fenix`, quant à lui, est destiné aux services que vous ne craignez pas de perdre entre les changements d'écran, mais lorsque vous avez besoin de ce service, vous vous attendez à ce qu'il soit vivant. Donc, fondamentalement, il supprimera le contrôleur / service / classe inutilisé, mais lorsque vous en aurez besoin, il "recréera à partir de ses cendres" une nouvelle instance.
Différences entre les méthodes:
- Get.put et Get.putAsync suivent le même ordre de création, à la différence que la seconde utilise une méthode asynchrone: ces deux méthodes créent et initialisent l'instance. Celle-ci est insérée directement dans la mémoire, en utilisant la méthode interne `insert` avec les paramètres` permanent: false` et `isSingleton: true` (ce paramètre isSingleton a pour seul but de dire s'il faut utiliser la dépendance sur` dependency` ou s'il doit utiliser la dépendance sur `FcBuilderFunc`). Après cela, `Get.find()` est appelé pour initialiser immédiatement les instances qui sont en mémoire.
- Get.create: Comme son nom l'indique, il "créera" votre dépendance! Similaire à `Get.put()`, il appelle également la méthode interne `insert` pour l'instanciation. Mais `permanent` devient vrai et` isSingleton` devient faux (puisque nous "créons" notre dépendance, il n'y a aucun moyen pour que ce soit une instance singleton, c'est pourquoi il est faux). Et comme il a `permanent: true`, nous avons par défaut l'avantage de ne pas le perdre entre les écrans! De plus, `Get.find()` n'est pas appelé immédiatement, il attend d'être utilisé dans l'écran pour être appelé. Il est créé de cette façon pour utiliser le paramètre `permanent`, depuis lors, il convient de noter que` Get.create() `a été créé dans le but de créer des instances non partagées, mais qui ne sont pas supprimées, comme par exemple un bouton dans un listView, pour lequel vous voulez une instance unique pour cette liste - à cause de cela, Get.create doit être utilisé avec GetWidget.
- Get.lazyPut: Comme son nom l'indique, il s'agit d'un processus 'paresseux'. L'instance est créée, mais elle n'est pas appelée pour être utilisée immédiatement, elle reste en attente d'être appelée. Contrairement aux autres méthodes, `insert` n'est pas appelé ici. Au lieu de cela, l'instance est insérée dans une autre partie de la mémoire, une partie chargée de dire si l'instance peut être recréée ou non, appelons-la "factory". Si nous voulons créer quelque chose pour être utilisé plus tard, il ne sera pas mélangé avec les choses actuellement utilisées. Et voici où la magie de `fenix` apparaît: si vous choisissez de laisser` fenix: false`, et que votre `smartManagement` n'est pas` keepFactory`, alors lors de l'utilisation de `Get.find`, l'instance changera la place dans la mémoire de la "factory" à la zone de mémoire d'instance commune. Juste après cela, par défaut, il est retiré de `la factory`. Maintenant, si vous optez pour `fenix: true`, l'instance continue d'exister dans cette partie dédiée, allant même vers la zone commune, pour être appelée à nouveau dans le futur.
## Bindings
L'une des grandes différences de ce package, peut-être, est la possibilité d'une intégration complète des routes, du gestionnaire d'état et du gestionnaire de dépendances.
Lorsqu'une route est supprimée de la pile, tous les contrôleurs, variables et instances d'objets qui lui sont associés sont supprimés de la mémoire. Si vous utilisez des streams ou timers, ils seront fermés automatiquement et vous n'aurez à vous soucier de rien de tout cela.
Dans la version 2.10, Get a complètement implémenté l'API Bindings.
Vous n'avez plus besoin d'utiliser la méthode init. Vous n'avez même pas besoin de `typer`(declaration de type) vos contrôleurs si vous ne le souhaitez pas. Vous pouvez démarrer vos contrôleurs et services à l'endroit approprié pour cela.
La classe Binding est une classe qui découplera l'injection de dépendances, en faisant du "binding" des routes entre le gestionnaire d'état et le gestionnaire de dépendances.
Cela permet à Get de savoir quel écran est affiché lorsqu'un contrôleur particulier est utilisé et de savoir où et comment s'en débarrasser.
De plus, la classe Binding vous permettra d'avoir le contrôle de la configuration de SmartManager. Vous pouvez configurer les dépendances à organiser lors de la suppression d'une route du Stack, ou lorsque le widget qui l'utilisait est disposé, ou ni l'un ni l'autre. Vous disposerez d'une gestion intelligente des dépendances qui fonctionnera pour vous, mais vous pourrez malgré tout la configurer comme vous le souhaitez.
### Classe Bindings
- Créer une classe et implémenter Bindings
```dart
class HomeBinding implements Bindings {}
```
Votre IDE vous demandera automatiquement de remplacer la méthode "dependencies", et il vous suffit de cliquer sur la lampe, de remplacer la méthode et d'insérer toutes les classes que vous allez utiliser sur cette route:
```dart
class HomeBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<HomeController>(() => HomeController());
Get.put<Service>(()=> Api());
}
}
class DetailsBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<DetailsController>(() => DetailsController());
}
}
```
Il vous suffit maintenant d'informer votre route, que vous utiliserez ce Binding pour établir la connexion entre le gestionnaire de routes, les dépendances et les états.
- En utilisant les routes nommées:
```dart
getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: HomeBinding(),
),
GetPage(
name: '/details',
page: () => DetailsView(),
binding: DetailsBinding(),
),
];
```
- En utilisant les routes normales:
```dart
Get.to(Home(), binding: HomeBinding());
Get.to(DetailsView(), binding: DetailsBinding())
```
Là, vous n'avez plus à vous soucier de la gestion de la mémoire de votre application, Get le fera pour vous.
La classe Binding est appelée lorsqu'une route est appelée, vous pouvez créer un "initialBinding dans votre GetMaterialApp pour insérer toutes les dépendances qui seront créées.
```dart
GetMaterialApp(
initialBinding: SampleBind(),
home: Home(),
);
```
### BindingsBuilder
La manière par défaut de créer un binding est de créer une classe qui implémente Bindings.
Mais alternativement, vous pouvez utiliser le callback `BindingsBuilder` afin de pouvoir simplement utiliser une fonction pour instancier ce que vous désirez.
Exemple:
```dart
getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: BindingsBuilder(() {
Get.lazyPut<ControllerX>(() => ControllerX());
Get.put<Service>(()=> Api());
}),
),
GetPage(
name: '/details',
page: () => DetailsView(),
binding: BindingsBuilder(() {
Get.lazyPut<DetailsController>(() => DetailsController());
}),
),
];
```
De cette façon, vous pouvez éviter de créer une classe Binding pour chaque route, ce qui est encore plus simple.
Les deux méthodes fonctionnent parfaitement bien et nous voulons que vous utilisiez ce qui correspond le mieux à vos goûts.
### SmartManagement
GetX par défaut supprime les contrôleurs inutilisés de la mémoire, même si un échec se produit et qu'un widget qui l'utilise n'est pas correctement supprimé.
C'est ce qu'on appelle le mode `full` de gestion des dépendances.
Mais si vous voulez changer la façon dont GetX contrôle la suppression des classes, vous avez la classe `SmartManagement` pour définir différents comportements.
#### Comment changer
Si vous souhaitez modifier cette configuration (dont vous n'avez généralement pas besoin), procédez comme suit:
```dart
void main () {
runApp(
GetMaterialApp(
smartManagement: SmartManagement.onlyBuilders //Ici
home: Home(),
)
)
}
```
#### SmartManagement.full
C'est celui par défaut. Supprime les classes qui ne sont pas utilisées et qui n'ont pas été définies pour être permanentes. Dans la majorité des cas, vous voudrez garder cette configuration intacte. Si vous débutez avec GetX, ne changez pas cela.
#### SmartManagement.onlyBuilders
Avec cette option, seuls les contrôleurs démarrés dans `init:` ou chargés dans un Binding avec `Get.lazyPut()` seront supprimés.
Si vous utilisez `Get.put()` ou `Get.putAsync()` ou toute autre approche, SmartManagement n'aura pas les autorisations pour exclure cette dépendance.
Avec le comportement par défaut, même les widgets instanciés avec "Get.put" seront supprimés, contrairement à SmartManagement.onlyBuilders.
#### SmartManagement.keepFactory
Tout comme SmartManagement.full, il supprimera ses dépendances lorsqu'elles ne seront plus utilisées. Cependant, il conservera leur factory, ce qui signifie qu'il recréera la dépendance si vous avez à nouveau besoin de cette instance.
### Comment Bindings fonctionne sous le capot
Bindings crée des `'factories' transitoires`, qui sont créées au moment où vous cliquez pour aller à un autre écran, et seront détruites dès que l'animation de changement d'écran se produit.
Cela arrive si vite que l'analyseur ne pourra même pas l'enregistrer.
Lorsque vous accédez à nouveau à cet écran, une nouvelle fabrique temporaire sera appelée, c'est donc préférable à l'utilisation de SmartManagement.keepFactory, mais si vous ne voulez pas créer de Bindings, ou si vous voulez garder toutes vos dépendances sur le même Binding , cela vous aidera certainement.
Les factories prennent peu de mémoire, elles ne contiennent pas d'instances, mais une fonction avec la "forme" de cette classe que vous voulez.
Cela a un très faible coût en mémoire, mais comme le but de cette bibliothèque est d'obtenir le maximum de performances possible en utilisant le minimum de ressources, Get supprime même les factories par défaut.
Utilisez celui qui vous convient le mieux.
## Notes
- N'UTILISEZ PAS SmartManagement.keepFactory si vous utilisez plusieurs Bindings. Il a été conçu pour être utilisé sans Bindings ou avec une seule Binding liée dans le fichier initialBinding de GetMaterialApp.
- L'utilisation de Bindings est complètement facultative, si vous le souhaitez, vous pouvez utiliser `Get.put()` et `Get.find()` sur les classes qui utilisent un contrôleur donné sans aucun problème.
Cependant, si vous travaillez avec des services ou toute autre abstraction, je vous recommande d'utiliser Bindings pour une meilleure organisation.
\ No newline at end of file
... ...
- [Gestion de route](#gestion-de-route)
- [Utilisation](#utilisation)
- [Navigation sans nom](#navigation-sans-nom)
- [Navigation par nom](#navigation-par-nom)
- [Envoyer des données aux routes nommées](#envoyer-des-donnes-aux-routes-nommes)
- [Liens URL dynamiques](#liens-url-dynamiques)
- [Middleware](#middleware)
- [Navigation sans context](#navigation-sans-context)
- [SnackBars](#snackbars)
- [Dialogs](#dialogs)
- [BottomSheets](#bottomsheets)
- [Nested Navigation](#nested-navigation)
# Gestion de route
C'est l'explication complète de tout ce qu'il y a à savoir sur Getx quand il s'agit de la gestion des routes.
## Utilisation
Ajoutez ceci à votre fichier pubspec.yaml:
```yaml
dependencies:
get:
```
Si vous allez utiliser des routes/snackbars/dialogs/bottomsheets sans contexte, ou utiliser les API Get de haut niveau, vous devez simplement ajouter "Get" avant votre MaterialApp, en le transformant en GetMaterialApp et en profiter!
```dart
GetMaterialApp( // Avant: MaterialApp(
home: MyHome(),
)
```
## Navigation sans nom
Pour accéder à un nouvel écran:
```dart
Get.to(NextScreen());
```
To close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);
Pour fermer les snackbars, dialogs, bottomsheets ou tout ce que vous fermez normalement avec Navigator.pop (context);
```dart
Get.back();
```
Pour aller à l'écran suivant et aucune option pour revenir à l'écran précédent (pour une utilisation dans SplashScreens, écrans de connexion, etc.)
```dart
Get.off(NextScreen());
```
Pour aller à l'écran suivant et annuler toutes les routes précédents (utile dans les paniers d'achat e-commerce, les sondages et les tests)
```dart
Get.offAll(NextScreen());
```
Pour naviguer vers l'écran suivant et recevoir ou mettre à jour des données dès que vous en revenez:
```dart
var data = await Get.to(Payment());
```
sur l'autre écran, envoyez les données pour l'écran précédent:
```dart
Get.back(result: 'success');
```
Et utilisez-les:
ex:
```dart
if(data == 'success') madeAnything();
```
Vous ne voulez pas apprendre notre syntaxe?
Changez simplement le Navigateur (majuscule) en navigateur (minuscule), et vous aurez toutes les fonctions de la navigation standard, sans avoir à utiliser 'context'.
Exemple:
```dart
// Navigateur Flutter par défaut
Navigator.of(context).push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return HomePage();
},
),
);
// Utilisez la syntaxe Flutter sans avoir besoin de 'context'
navigator.push(
MaterialPageRoute(
builder: (_) {
return HomePage();
},
),
);
// Syntaxe Get (c'est beaucoup mieux, mais vous avez le droit d'être en désaccord)
Get.to(HomePage());
```
## Navigation Par Nom
- Si vous préférez naviguer par namedRoutes, Get prend également en charge cela.
Pour aller à nextScreen
```dart
Get.toNamed("/NextScreen");
```
Pour naviguer et supprimer l'écran précédent du stack.
```dart
Get.offNamed("/NextScreen");
```
Pour naviguer et supprimer tous les écrans précédents du stack.
```dart
Get.offAllNamed("/NextScreen");
```
Pour définir des routes, utilisez GetMaterialApp:
```dart
void main() {
runApp(
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.zoom
),
],
)
);
}
```
Pour gérer la navigation vers des routes non définies (erreur 404), vous pouvez définir une page 'unknownRoute' dans GetMaterialApp.
```dart
void main() {
runApp(
GetMaterialApp(
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
],
)
);
}
```
### Envoyer des données aux routes nommées
Envoyez simplement ce que vous voulez comme arguments. Get accepte n'importe quoi ici, qu'il s'agisse d'une String, d'une Map, d'une List ou même d'une instance de classe.
```dart
Get.toNamed("/NextScreen", arguments: 'Get is the best');
```
dans votre classe ou contrôleur:
```dart
print(Get.arguments);
//montre: Get is the best
```
### Liens URL dynamiques
Get propose des URL dynamiques avancées, tout comme sur le Web. Les développeurs Web ont probablement déjà voulu cette fonctionnalité sur Flutter, et ont très probablement vu un package promettre cette fonctionnalité et fournir une syntaxe totalement différente de celle d'une URL sur le Web, mais Get résout également cela.
```dart
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");
```
sur votre classe controller/bloc/stateful/stateless:
```dart
print(Get.parameters['id']);
// donne: 354
print(Get.parameters['name']);
// donne: Enzo
```
Vous pouvez également recevoir facilement des paramètres nommés avec Get:
```dart
void main() {
runApp(
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(
name: '/',
page: () => MyHomePage(),
),
GetPage(
name: '/profile/',
page: () => MyProfile(),
),
//Vous pouvez définir une page différente pour les routes avec arguments, et une autre sans arguments, mais pour cela vous devez utiliser la barre oblique '/' sur la route qui ne recevra pas d'arguments comme ci-dessus.
GetPage(
name: '/profile/:user',
page: () => UserProfile(),
),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.cupertino
),
],
)
);
}
```
Envoyer des données sur le nom de la route
```dart
Get.toNamed("/profile/34954");
```
Sur le deuxième écran, recevez les données par paramètre
```dart
print(Get.parameters['user']);
// donne: 34954
```
ou envoyer plusieurs paramètres comme celui-ci
```dart
Get.toNamed("/profile/34954?flag=true");
```
Sur le deuxième écran, prenez les données par paramètres comme d'habitude
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
// donne: 34954 true
```
Et maintenant, tout ce que vous avez à faire est d'utiliser Get.toNamed() pour parcourir vos routes nommées, sans aucun contexte (vous pouvez appeler vos routes directement à partir de votre classe BLoC ou Controller), et lorsque votre application est compilée sur le Web, vos routes apparaîtront dans l'url <3
### Middleware
Si vous souhaitez écouter les événements Get pour déclencher des actions, vous pouvez utiliser routingCallback pour le faire:
```dart
GetMaterialApp(
routingCallback: (routing) {
if(routing.current == '/second'){
openAds();
}
}
)
```
Si vous n'utilisez pas GetMaterialApp, vous pouvez utiliser l'API manuelle pour attacher l'observateur Middleware.
```dart
void main() {
runApp(
MaterialApp(
onGenerateRoute: Router.generateRoute,
initialRoute: "/",
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer), // ICI !!!
],
),
);
}
```
Créez une classe MiddleWare
```dart
class MiddleWare {
static observer(Routing routing) {
/// Vous pouvez écouter en plus des routes, des snackbars, des dialogs et des bottomsheets sur chaque écran.
/// Si vous devez saisir l'un de ces 3 événements directement ici,
/// vous devez spécifier que l'événement est != Ce que vous essayez de faire.
if (routing.current == '/second' && !routing.isSnackbar) {
Get.snackbar("Hi", "You are on second route");
} else if (routing.current =='/third'){
print('dernière route');
}
}
}
```
Maintenant, utilisez Get sur votre code:
```dart
class First extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
Get.snackbar("hi", "i am a modern snackbar");
},
),
title: Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/second");
},
),
),
);
}
}
class Second extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
Get.snackbar("hi", "i am a modern snackbar");
},
),
title: Text('second Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/third");
},
),
),
);
}
}
class Third extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Third Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Get.back();
},
child: Text('Go back!'),
),
),
);
}
}
```
## Navigation sans context
### SnackBars
Pour avoir un simple SnackBar avec Flutter, vous devez obtenir le 'context' de Scaffold, ou vous devez utiliser un GlobalKey attaché à votre Scaffold
```dart
final snackBar = SnackBar(
content: Text('Hi!'),
action: SnackBarAction(
label: 'I am a old and ugly snackbar :(',
onPressed: (){}
),
);
// Trouvez le scaffold dans l'arborescence des widgets et utilisez-le pour afficher un SnackBar.
Scaffold.of(context).showSnackBar(snackBar);
```
Avec Get:
```dart
Get.snackbar('Hi', 'i am a modern snackbar');
```
Avec Get, tout ce que vous avez à faire est d'appeler votre Get.snackbar à partir de n'importe où dans votre code ou de le personnaliser comme vous le souhaitez!
```dart
Get.snackbar(
"Hey i'm a Get SnackBar!", // title
"C'est incroyable! J'utilise SnackBar sans context, sans code standard, sans Scaffold, c'est quelque chose de vraiment incroyable!", // message
icon: Icon(Icons.alarm),
shouldIconPulse: true,
onTap:(){},
barBlur: 20,
isDismissible: true,
duration: Duration(seconds: 3),
);
////////// TOUTES LES FONCTIONNALITÉS //////////
// Color colorText,
// Duration duration,
// SnackPosition snackPosition,
// Widget titleText,
// Widget messageText,
// bool instantInit,
// Widget icon,
// bool shouldIconPulse,
// double maxWidth,
// EdgeInsets margin,
// EdgeInsets padding,
// double borderRadius,
// Color borderColor,
// double borderWidth,
// Color backgroundColor,
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
// AnimationController progressIndicatorController,
// Color progressIndicatorBackgroundColor,
// Animation<Color> progressIndicatorValueColor,
// SnackStyle snackStyle,
// Curve forwardAnimationCurve,
// Curve reverseAnimationCurve,
// Duration animationDuration,
// double barBlur,
// double overlayBlur,
// Color overlayColor,
// Form userInputForm
///////////////////////////////////
```
Si vous préférez le snack-bar traditionnel, ou souhaitez le personnaliser à partir de zéro, y compris en ajoutant une seule ligne (Get.snackbar utilise un titre et un message obligatoires), vous pouvez utiliser
`Get.rawSnackbar ();` qui fournit l'API brute sur laquelle Get.snackbar a été construit.
### Dialogs
Pour ouvrir un 'dialog':
```dart
Get.dialog(VotreDialogWidget());
```
Pour ouvrir le 'dialog' par défaut:
```dart
Get.defaultDialog(
onConfirm: () => print("Ok"),
middleText: "Dialog made in 3 lines of code"
);
```
Vous pouvez également utiliser Get.generalDialog au lieu de showGeneralDialog.
Pour tous les autres widgets de la boîte de dialogue Flutter, y compris cupertinos, vous pouvez utiliser Get.overlayContext au lieu du context et l'ouvrir n'importe où dans votre code.
Pour les widgets qui n'utilisent pas Overlay, vous pouvez utiliser Get.context.
Ces deux contextes fonctionneront dans 99% des cas pour remplacer le context de votre interface utilisateur, sauf dans les cas où inheritedWidget est utilisé sans context de navigation.
### BottomSheets
Get.bottomSheet est comme showModalBottomSheet, mais n'a pas besoin de 'context'.
```dart
Get.bottomSheet(
Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () {},
),
],
),
)
);
```
## Nested Navigation
Getx a rendu la navigation imbriquée de Flutter encore plus facile.
Vous n'avez pas besoin de 'context' et vous trouverez votre stack de navigation par ID.
- NOTE: La création de stacks de navigation parallèles peut être dangereuse. L'idéal est de ne pas utiliser NestedNavigators, ou de l'utiliser avec parcimonie. Si votre projet l'exige, allez-y, mais gardez à l'esprit que conserver plusieurs stacks de navigation en mémoire n'est peut-être pas une bonne idée pour la consommation de RAM.
Voyez comme c'est simple:
```dart
Navigator(
key: Get.nestedKey(1), // créez une clé par index
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name == '/') {
return GetPageRoute(
page: () => Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // naviguer votre itinéraire imbriqué par index
},
child: Text("Go to second"),
),
),
),
);
} else if (settings.name == '/second') {
return GetPageRoute(
page: () => Center(
child: Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: Text("second")
),
),
),
);
}
}
),
```
... ...
- [Gestion d'État](#gestion-d-etat)
- [Gestionnaire d'état réactif](#gestionnaire-d-etat-reactif)
- [Avantages](#avantages)
- [Performance maximale:](#performance-maximale)
- [Déclaration d'une variable réactive](#declaration-d-une-variable-reactive)
- [Avoir un état réactif, c'est facile.](#avoir-un-etat-reactif-c-est-facile)
- [Utilisation des valeurs dans la Vue](#utilisation-des-valeurs-dans-la-vue)
- [Conditions pour reconstruire](#conditions-pour-reconstruire)
- [Quand utiliser .obs](#quand-utiliser-obs)
- [Remarque sur List](#remarque-sur-list)
- [Pourquoi je dois utiliser .value](#pourquoi-je-dois-utiliser-value)
- [Obx()](#obx)
- [Workers](#workers)
- [Gestionnaire d'état simple](#gestionnaire-d-etat-simple)
- [Atouts](#atouts)
- [Utilisation](#utilisation)
- [Comment il gère les contrôleurs](#comment-il-gre-les-contrleurs)
- [Vous n'aurez plus besoin de StatefulWidgets](#vous-naurez-plus-besoin-de-statefulwidgets)
- [Pourquoi ça existe](#pourquoi-ca-existe)
- [Autres façons de l'utiliser](#autres-formes-d-utilisation)
- [IDs Uniques](#ids-uniques)
- [Mélanger les deux gestionnaires d'état](#mixing-the-two-state-managers)
- [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)
# Gestion d Etat
GetX n'utilise pas Streams ou ChangeNotifier comme les autres gestionnaires d'état. Pourquoi? En plus de créer des applications pour Android, iOS, Web, Linux, MacOS et Linux, GetX vous permet de créer des applications serveur avec la même syntaxe que Flutter / GetX. Afin d'améliorer le temps de réponse et de réduire la consommation de RAM, nous avons créé GetValue et GetStream, des solutions à faible latence qui offrent beaucoup de performances, à un faible coût d'exploitation. Nous utilisons cette base pour construire toutes nos ressources, y compris la gestion d'état.
- _Complexité_: Certains gestionnaires d'État sont complexes et ont beaucoup de code standard. Avec GetX, vous n'avez pas à définir une classe pour chaque événement, le code est très propre et clair, et vous faites beaucoup plus en écrivant moins. Beaucoup de gens ont abandonné Flutter à cause de ce sujet, et ils ont enfin une solution stupidement simple pour gérer les états.
- _Aucun générateur de code_: Vous passez la moitié de votre temps de développement à écrire la logique de votre application. Certains gestionnaires d'état s'appuient sur des générateurs de code pour avoir un code lisible minimal. Changer une variable et avoir à exécuter build_runner peut être improductif, et souvent le temps d'attente après un redémarrage sera long, et vous devrez boire beaucoup de café.
Avec GetX, tout est réactif, et rien ne dépend des générateurs de code, augmentant votre productivité dans tous les aspects de votre développement.
- _Cela ne dépend pas de 'context'_: Vous avez probablement déjà eu besoin d'envoyer le contexte de votre vue à un contrôleur, ce qui rend le couplage de la vue avec votre logique métier élevé. Vous avez probablement dû utiliser une dépendance dans un endroit qui n'a pas de contexte, et avez dû passer le contexte à travers différentes classes et fonctions. Cela n'existe tout simplement pas avec GetX. Vous avez accès à vos contrôleurs depuis vos contrôleurs sans aucun contexte. Vous n'avez pas besoin d'envoyer le contexte par paramètre pour rien.
- _Contrôle granulaire_: la plupart des gestionnaires d'état sont basés sur ChangeNotifier. ChangeNotifier notifiera tous les widgets qui en dépendent lors de l'appel de notifyListeners. Si vous avez 40 widgets sur un écran, qui ont une variable de votre classe ChangeNotifier, lorsque vous en mettez un à jour, tous seront reconstruits.
Avec GetX, même les widgets imbriqués sont respectés. Si Obx gère votre ListView et un autre gère une case à cocher dans ListView, lors de la modification de la valeur CheckBox, il ne sera mis à jour que, lors de la modification de la valeur List, seul le ListView sera mis à jour.
- _Il ne reconstruit que si sa variable change VRAIMENT_: GetX a un contrôle de flux, cela signifie que si vous affichez un texte avec 'Paola', si vous changez à nouveau la variable observable en 'Paola', le widget ne sera pas reconstruit. C'est parce que GetX sait que `Paola` est déjà affiché dans Text et ne fera pas de reconstructions inutiles.
La plupart (sinon tous) les gestionnaires d'état actuels se reconstruiront à l'écran.
## Gestionnaire d etat reactif
La programmation réactive peut aliéner de nombreuses personnes car on dit qu'elle est compliquée. GetX transforme la programmation réactive en quelque chose d'assez simple:
- Vous n'aurez pas besoin de créer des StreamControllers.
- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable
- Vous n'aurez pas besoin de créer une classe pour chaque état.
- Vous n'aurez pas besoin de créer un 'get' pour une valeur initiale.
La programmation réactive avec Get est aussi simple que d'utiliser setState.
Imaginons que vous ayez une variable de 'name' et que vous souhaitiez que chaque fois que vous la modifiez, tous les widgets qui l'utilisent soient automatiquement modifiés.
Voici votre variable:
```dart
var name = 'Jonatas Borges';
```
Pour la rendre observable, il vous suffit d'ajouter ".obs" à la fin:
```dart
var name = 'Jonatas Borges'.obs;
```
C'est *tout*. Si simple que ca.
A partir de maintenant, nous pourrions désigner ces variables réactives - ". Obs" (ervables) comme _Rx_.
Qu'est ce qui s'est passé derrière les rideaux? Nous avons créé un `Stream` de` String`s, assigné la valeur initiale `" Jonatas Borges "`, nous avons notifié tous les widgets qui utilisent `" Jonatas Borges "` qu'ils "appartiennent" maintenant à cette variable, et quand la valeur _Rx_ changements, ils devront également changer.
C'est la **magie de GetX**, grâce aux performances de Dart.
Mais, comme nous le savons, un `Widget` ne peut être changé que s'il est à l'intérieur d'une fonction, car les classes statiques n'ont pas le pouvoir de" changer automatiquement ".
Vous devrez créer un `StreamBuilder`, vous abonner à cette variable pour écouter les changements et créer une" cascade "de` StreamBuilder` imbriqués si vous voulez changer plusieurs variables dans la même portée, non?
Non, vous n'avez pas besoin d'un `StreamBuilder`, mais vous avez raison pour les classes statiques.
Eh bien, dans la vue, nous avons généralement beaucoup de code standard lorsque nous voulons changer un widget spécifique, c'est la manière Flutter.
Avec **GetX**, vous pouvez également oublier ce code passe-partout.
`StreamBuilder( … )`? `initialValue: …`? `builder: …`? Non, il vous suffit de placer cette variable dans un widget `Obx()`.
```dart
Obx (() => Text (controller.name));
```
_Que devez-vous mémoriser?_ Seulement `Obx(() =>`.
Vous passez simplement ce Widget via une fonction dans un `Obx()` (l' "Observateur" du _Rx_).
`Obx` est assez intelligent et ne changera que si la valeur de` controller.name` change.
Si `name` est` "John" `, et que vous le changez en` "John" `(` name.value = "John" `), comme c'est la même` valeur` qu'avant, rien ne changera à l'écran, et `Obx`, pour économiser les ressources, ignorera simplement la nouvelle valeur et ne reconstruira pas le widget. **N'est-ce pas incroyable?**
> Alors, que faire si j'ai 5 variables _Rx_ (observables) dans un `Obx`?
Il sera simplement mis à jour lorsque **l'un d'entre eux** change.
> Et si j'ai 30 variables dans une classe, lorsque j'en mets une à jour, est-ce que cela va mettre à jour **toutes** les variables qui sont dans cette classe?
Non, juste le **Widget spécifique** qui utilise cette variable _Rx_.
Ainsi, **GetX** ne met à jour l'écran que lorsque la variable _Rx_ change sa valeur.
```
final isOpen = false.obs;
// Rien de ne change... valeur identique.
void onButtonTap() => isOpen.value=false;
```
### Avantages
**GetX()** vous aide lorsque vous avez besoin d'un contrôle **granulaire** sur ce qui est mis à jour.
Si vous n'avez pas besoin d'ID uniques, car toutes vos variables seront modifiées lorsque vous effectuez une action, utilisez `GetBuilder`,
parce que c'est un Simple State Updater (en blocs, comme `setState()`), fait en seulement quelques lignes de code.
Il a été rendu simple, pour avoir le moins d'impact sur le processeur, et juste pour remplir un seul objectif (une reconstruction de _l'état_) et dépenser le minimum de ressources possible.
Si vous avez besoin d'un State Manager **puissant** , vous ne pouvez pas vous tromper avec **GetX**.
Cela ne fonctionne pas avec les variables, mais __flows__, tout ce qu'il contient sont des `Streams` en réalité.
Vous pouvez utiliser _rxDart_ en conjonction avec lui, car tout est `Streams`.
Vous pouvez écouter les changements de chaque "variable _Rx_",
parce que tout ce qui se trouve dedans est un `Streams`.
C'est littéralement une approche _BLoC_, plus facile que _MobX_, et sans générateurs de code ni décorations.
Vous pouvez transformer **n'importe quoi** en un _"Observable"_ avec juste un `.obs`.
### Performance maximale:
En plus d'avoir un algorithme intelligent pour des reconstructions minimales, **GetX** utilise des comparateurs
pour s'assurer que l'État a changé.
Si vous rencontrez des erreurs dans votre application et envoyez un changement d'état en double,
**GetX** garantira qu'il ne plantera pas.
Avec **GetX**, l'état ne change que si la `valeur` change.
C'est la principale différence entre **GetX** et l'utilisation de _`computed` de MobX_.
Lors de la jonction de deux __observables__, si l'une change; le listener de cet _observable_ changera également.
Avec **GetX**, si vous joignez deux variables, `GetX()` (similaire à `Observer()`), ne se reconstruira que si cela implique un réel changement d'état.
### Declaration d une variable reactive
Vous avez 3 façons de transformer une variable en "observable".
1 - La première est d'utiliser **`Rx{Type}`**.
```dart
// la valeur initiale est recommandée, mais pas obligatoire
final name = RxString('');
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({});
```
2 - La seconde consiste à utiliser **`Rx`** et à utiliser les types `Rx<Type>` Génériques Darts
```dart
final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0);
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({});
// Classes personnalisées - il peut s'agir de n'importe quelle classe, littéralement
final user = Rx<User>();
```
3 - La troisième approche, plus pratique, plus facile et préférée, ajoutez simplement **`.obs`** comme propriété de votre` valeur`:
```dart
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// Classes personnalisées - il peut s'agir de n'importe quelle classe, littéralement
final user = User().obs;
```
##### Avoir un etat reactif, c est facile.
Comme nous le savons, _Dart_ se dirige maintenant vers _null safety_.
Pour être prêt, à partir de maintenant, vous devez toujours commencer vos variables _Rx_ avec une **valeur initiale**.
> Transformer une variable en _observable_ + _valeurInitiale_ avec **GetX** est l'approche la plus simple et la plus pratique.
Vous allez littéralement ajouter un "".obs"" à la fin de votre variable, et **c'est tout**, vous l'avez rendue observable,
et sa `.value`, eh bien, sera la _valeurInitiale_.
### Utilisation des valeurs dans la Vue
```dart
// dans le controlleur
final count1 = 0.obs;
final count2 = 0.obs;
int get sum => count1.value + count2.value;
```
```dart
// dans la vue
GetX<Controller>(
builder: (controller) {
print("count 1 reconstruction");
return Text('${controller.count1.value}');
},
),
GetX<Controller>(
builder: (controller) {
print("count 2 reconstruction");
return Text('${controller.count2.value}');
},
),
GetX<Controller>(
builder: (controller) {
print("count 3 reconstruction");
return Text('${controller.sum}');
},
),
```
Si nous incrémentons `count1.value++`, cela affichera:
- `count 1 reconstruction`
- `count 3 reconstruction`
parce que `count1` a une valeur de `1`, et `1 + 0 = 1`, changeant la valeur du getter `sum`.
Si nous incrémentons `count2.value++`, cela affichera:
- `count 2 reconstruction`
- `count 3 reconstruction`
parce que `count2.value` a changé et que le résultat de `sum` est maintenant `2`.
- NOTE: Par défaut, le tout premier événement reconstruira le widget, même s'il s'agit de la même `valeur`.
Ce comportement existe en raison de variables booléennes.
Imaginez que vous fassiez ceci:
```dart
var isLogged = false.obs;
```
Et puis, vous vérifiez si un utilisateur est "connecté" pour déclencher un événement dans `ever`.
```dart
@override
onInit(){
ever(isLogged, fireRoute);
isLogged.value = await Preferences.hasToken();
}
fireRoute(logged) {
if (logged) {
Get.off(Home());
} else {
Get.off(Login());
}
}
```
si `hasToken` était `false`, il n'y aurait pas de changement à `isLogged`, donc` ever() `ne serait jamais appelé.
Pour éviter ce type de comportement, la première modification d'un _observable_ déclenchera toujours un événement,
même s'il contient la même `.value`.
Vous pouvez supprimer ce comportement si vous le souhaitez, en utilisant:
`isLogged.firstRebuild = false;`
### Conditions pour reconstruire
En outre, Get fournit un contrôle d'état raffiné. Vous pouvez conditionner un événement (comme l'ajout d'un objet à une liste), à ​​une certaine condition.
```dart
// Premier paramètre: condition, doit retourner vrai ou faux.
// Deuxième paramètre: la nouvelle valeur à appliquer si la condition est vraie.
list.addIf(item < limit, item);
```
Sans décorations, sans générateur de code, sans complications :smile:
Connaissez-vous l'application 'counter' de Flutter? Votre classe Controller pourrait ressembler à ceci:
```dart
class CountController extends GetxController {
final count = 0.obs;
}
```
Avec un simple:
```dart
controller.count.value++
```
Vous pouvez mettre à jour la variable de compteur dans votre interface utilisateur, quel que soit l'endroit où elle est stockée.
### Quand utiliser .obs
Vous pouvez tout transformer sur obs. Voici deux façons de procéder:
* Vous pouvez convertir vos valeurs de classe en obs
```dart
class RxUser {
final name = "Camila".obs;
final age = 18.obs;
}
```
* ou vous pouvez convertir la classe entière en un observable:
```dart
class User {
User({String name, int age});
var name;
var age;
}
// en instanciant:
final user = User(name: "Camila", age: 18).obs;
```
### Remarque sur List
Les listes sont complètement observables, tout comme les objets qu'elles contiennent. De cette façon, si vous ajoutez une valeur à une liste, cela reconstruira automatiquement les widgets qui l'utilisent.
Vous n'avez pas non plus besoin d'utiliser ".value" avec des listes, l'incroyable api de Dart nous a permis de supprimer cela.
Malheureusement, les types primitifs comme String et int ne peuvent pas être étendus, ce qui rend l'utilisation de .value obligatoire, mais ce ne sera pas un problème si vous travaillez avec des getters et des setters pour ceux-ci.
```dart
// Dans le controlleur
final String title = 'User Info:'.obs;
final list = List<User>().obs;
// Dans la vue
Text(controller.title.value), // La String doit avoir .value devant elle
ListView.builder (
itemCount: controller.list.length // pas besoin pour List
)
```
Lorsque vous rendez vos propres classes observables, il existe une manière différente de les mettre à jour:
```dart
// sur le fichier modèle
// nous allons rendre la classe entière observable au lieu de chaque attribut
class User() {
User({this.name = '', this.age = 0});
String name;
int age;
}
// Dans le controlleur
final user = User().obs;
// lorsque vous devez mettre à jour la variable utilisateur:
user.update( (user) { // ce paramètre est la classe même que vous souhaitez mettre à jour
user.name = 'Jonny';
user.age = 18;
});
// une autre manière de mettre à jour la variable user:
user(User(name: 'João', age: 35));
// Dans la vue:
Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}"))
// vous pouvez également accéder aux valeurs du modèle sans le .value:
user().name; //notez que c'est la variable utilisateur, pas la classe (la variable a un u minuscule)
```
Vous n'êtes pas obligé de travailler avec des setters si vous ne le souhaitez pas. vous pouvez utiliser les API `assign` et `assignAll`.
L'API `assign` effacera votre liste et ajoutera un seul objet que vous souhaitez.
L'API `assignAll` effacera la liste existante et ajoutera tous les objets itérables que vous y injecterez.
### Pourquoi je dois utiliser .value
Nous pourrions supprimer l'obligation d'utiliser 'value' pour `String` et` int` avec une simple décoration et un générateur de code, mais le but de cette bibliothèque est précisément d'éviter les dépendances externes. Nous souhaitons proposer un environnement prêt à la programmation, impliquant l'essentiel (gestion des routes, des dépendances et des états), de manière simple, légère et performante, sans avoir besoin d'un package externe.
Vous pouvez littéralement ajouter 3 lettres à votre pubspec (get) et un signe deux-points et commencer la programmation. Toutes les solutions incluses par défaut, de la gestion des routes à la gestion des états, visent la facilité, la productivité et la performance.
Le poids total de cette bibliothèque est inférieur à celui d'un seul gestionnaire d'état, bien qu'il s'agisse d'une solution complète, et c'est ce que vous devez comprendre.
Si vous êtes dérangé par `.value`, et comme un générateur de code, MobX est une excellente alternative, et vous pouvez l'utiliser en conjonction avec Get. Pour ceux qui veulent ajouter une seule dépendance dans pubspec et commencer à programmer sans se soucier de l'incompatibilité de la version d'un package avec un autre, ou si l'erreur d'une mise à jour d'état vient du gestionnaire d'état ou de la dépendance, ou encore, ne veulent pas s'inquiéter de la disponibilité des contrôleurs, que ce soit littéralement "juste de la programmation", get est tout simplement parfait.
Si vous n'avez aucun problème avec le générateur de code MobX, ou si vous n'avez aucun problème avec le code standard BLoC, vous pouvez simplement utiliser Get pour les routes et oublier qu'il a un gestionnaire d'état. Get SEM et RSM sont nés par nécessité, mon entreprise avait un projet avec plus de 90 contrôleurs, et le générateur de code a simplement pris plus de 30 minutes pour terminer ses tâches après un Flutter Clean sur une machine raisonnablement bonne, si votre projet il a 5, 10, 15 contrôleurs, n'importe quel gestionnaire d'état vous suffira bien. Si vous avez un projet d'une taille absurde et que le générateur de code est un problème pour vous, cette solution vous a été attribuée.
Évidemment, si quelqu'un veut contribuer au projet et créer un générateur de code, ou quelque chose de similaire, je vais créer un lien dans ce readme comme alternative, mon besoin n'est pas le besoin de tous les développeurs, mais pour l'instant je dis q'il y a de bonnes solutions qui font déjà cela, comme MobX.
### Obx()
Les types dans Get à l'aide de Bindings ne sont pas nécessaires. Vous pouvez utiliser le widget Obx, au lieu de GetX, qui ne reçoit que la fonction anonyme qui crée un widget.
Évidemment, si vous n'utilisez pas de type, vous devrez avoir une instance de votre contrôleur pour utiliser les variables, ou utiliser `Get.find<Controller>()` .value ou Controller.to.value pour récupérer la valeur .
### Workers
Les 'workers' vous assisteront, déclenchant des callbacks spécifiques lorsqu'un événement se produit.
```dart
/// Appelée à chaque fois que `count1` change.
ever(count1, (_) => print("$_ a été modifié"));
/// Appelée uniquement la première fois que la variable est modifiée
once(count1, (_) => print("$_ a été changé une fois"));
/// Anti DDos - Appelée chaque fois que l'utilisateur arrête de taper pendant 1 seconde, par exemple.
debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));
/// Ignore toutes les modifications pendant 1 seconde.
interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));
```
Tous les workers (sauf `debounce`) ont un paramètre nommé `condition`, qui peut etre un `bool` ou un callback qui retourne un `bool`.
Cette `condition` definit quand la fonction `callback` est executée.
Tous les workers renvoyent un objet `Worker`, qui peut être utilisé pour annuler ( via `dispose()` ) le `worker`.
- **`ever`**
est appelée chaque fois que la variable _Rx_ émet une nouvelle valeur.
- **`everAll`**
Un peu comme `ever`, mais il prend une` List` de valeurs _Rx_. Appelée chaque fois que sa variable est changée. C'est tout.
- **`once`**
'once' est appelée uniquement la première fois que la variable a été modifiée.
- **`debounce`**
'debounce' est très utile dans les fonctions de recherche, où vous souhaitez que l'API ne soit appelée que lorsque l'utilisateur a fini de taper. Si l'utilisateur tape "Jonny", vous aurez 5 recherches dans les API, par la lettre J, o, n, n et y. Avec Get, cela ne se produit pas, car vous aurez un Worker "anti-rebond" qui ne sera déclenché qu'à la fin de la saisie.
- **`interval`**
'interval' est différent de 'debounce'. Avec `debounce` si l'utilisateur fait 1000 changements à une variable en 1 seconde, il n'enverra que le dernier après le temporisateur stipulé (la valeur par défaut est 800 millisecondes). 'Interval' ignorera à la place toutes les actions de l'utilisateur pour la période stipulée. Si vous envoyez des événements pendant 1 minute, 1000 par seconde, debounce ne vous enverra que le dernier, lorsque l'utilisateur arrête de mitrailler les événements. interval délivrera des événements toutes les secondes, et s'il est réglé sur 3 secondes, il fournira 20 événements cette minute. Ceci est recommandé pour éviter les abus, dans des fonctions où l'utilisateur peut rapidement cliquer sur quelque chose et obtenir un avantage (imaginez que l'utilisateur puisse gagner des pièces en cliquant sur quelque chose, s'il cliquait 300 fois dans la même minute, il aurait 300 pièces, en utilisant l'intervalle, vous pouvez définir une période de 3 secondes, et même en cliquant 300 ou mille fois, le maximum qu'il obtiendrait en 1 minute serait de 20 pièces, en cliquant 300 ou 1 million de fois). Le 'debounce' convient aux anti-DDos, pour des fonctions comme la recherche où chaque changement de onChange entraînerait une requête à votre api. Debounce attendra que l'utilisateur arrête de taper le nom, pour faire la demande. S'il était utilisé dans le scénario de pièces mentionné ci-dessus, l'utilisateur ne gagnerait qu'une pièce, car il n'est exécuté que lorsque l'utilisateur "fait une pause" pendant le temps établi.
- NOTE: Les 'workers' doivent toujours être utilisés lors du démarrage d'un contrôleur ou d'une classe, il doit donc toujours être dans onInit (recommandé), le constructeur de classe ou l'initState d'un StatefulWidget (cette pratique n'est pas recommandée dans la plupart des cas, mais cela ne devrait poser aucun problème).
## Gestionnaire d etat simple
Get a un gestionnaire d'état extrêmement léger et facile, qui n'utilise pas ChangeNotifier, répondra aux besoins en particulier des nouveaux utilisateurs de Flutter et ne posera pas de problèmes pour les applications volumineuses.
GetBuilder vise précisément le contrôle de plusieurs états. Imaginez que vous avez ajouté 30 produits à un panier, que vous cliquez sur supprimer un, en même temps que la liste est mise à jour, le prix est mis à jour et le badge dans le panier est mis à jour avec un nombre plus petit. Ce type d'approche fait de GetBuilder un tueur, car il regroupe les états et les modifie tous à la fois sans aucune "logique de calcul" pour cela. GetBuilder a été créé avec ce type de situation à l'esprit, car pour un changement d'état éphémère, vous pouvez utiliser setState et vous n'aurez pas besoin d'un gestionnaire d'état pour cela.
De cette façon, si vous voulez un contrôleur individuel, vous pouvez lui attribuer des ID ou utiliser GetX. Cela dépend de vous, en vous rappelant que plus vous avez de widgets "individuels", plus les performances de GetX se démarqueront, tandis que les performances de GetBuilder devraient être supérieures, en cas de changement d'état multiple.
### Atouts
1. Met à jour uniquement les widgets requis.
2. N'utilise pas changeNotifier, c'est le gestionnaire d'état qui utilise le moins de mémoire (proche de 0 Mo).
3. Oubliez StatefulWidget! Avec Get, vous n'en aurez jamais besoin. Avec les autres gestionnaires d'états, vous devrez probablement utiliser un StatefulWidget pour obtenir l'instance de votre fournisseur, BLoC, MobX Controller, etc. Mais vous êtes-vous déjà arrêté pour penser que votre appBar, votre 'scaffold', et la plupart des les widgets de votre classe sont sans état (stateless)? Alors pourquoi sauvegarder l'état d'une classe entière, si vous pouvez sauvegarder l'état du widget qui est `avec état` (statefull)? Get résout cela aussi. Créez une classe sans état, rendez tout `sans état`. Si vous devez mettre à jour un seul composant, enveloppez-le avec GetBuilder et son état sera conservé.
4. Organisez votre projet pour de vrai! Les contrôleurs ne doivent pas être dans votre interface utilisateur, placer votre TextEditController ou tout contrôleur que vous utilisez dans votre classe Controller.
5. Avez-vous besoin de déclencher un événement pour mettre à jour un widget dès son rendu? GetBuilder a la propriété "initState", tout comme StatefulWidget, et vous pouvez appeler des événements depuis votre contrôleur, directement depuis celui-ci, aucun événement n'étant placé dans votre initState.
6. Avez-vous besoin de déclencher une action comme la fermeture de stream, de timers, etc.? GetBuilder a également la propriété dispose(), où vous pouvez appeler des événements dès que ce widget est détruit.
7. N'utilisez les streams que si nécessaire. Vous pouvez utiliser vos StreamControllers à l'intérieur de votre contrôleur normalement, et utiliser StreamBuilder également normalement, mais rappelez-vous qu'un stream consomme raisonnablement de la mémoire, la programmation réactive est belle, mais vous ne devriez pas en abuser. 30 streams ouverts simultanément peuvent être pires que changeNotifier (et changeNotifier est très mauvais).
8. Mettez à jour les widgets sans dépenser de RAM pour cela. Get stocke uniquement l'ID de créateur GetBuilder et met à jour ce GetBuilder si nécessaire. La consommation de mémoire du stockage get ID en mémoire est très faible, même pour des milliers de GetBuilders. Lorsque vous créez un nouveau GetBuilder, vous partagez en fait l'état de GetBuilder qui a un ID de créateur. Un nouvel état n'est pas créé pour chaque GetBuilder, ce qui économise BEAUCOUP de RAM pour les applications volumineuses. Fondamentalement, votre application sera entièrement sans état (stateless), et les quelques widgets qui seront stateful (dans GetBuilder) auront un seul état, et par conséquent, la mise à jour d'un seul les mettra tous à jour. L'état est unique.
9. Get est omniscient et, dans la plupart des cas, il sait exactement quand sortir de mémoire un contrôleur. Vous ne devez pas vous soucier du moment de vous débarrasser d'un contrôleur, Get connaît le meilleur moment pour le faire.
### Utilisation
```dart
// Créez la classe controller qui 'extends' GetxController
class Controller extends GetxController {
int counter = 0;
void increment() {
counter++;
update(); // utilisez update() pour mettre à jour la variable de compteur sur l'interface utilisateur lorsque incrément() est appelé
}
}
// Sur votre classe Stateless / Stateful, utilisez GetBuilder pour mettre à jour le texte lorsque incrément() est appelé
GetBuilder<Controller>(
init: Controller(), // INITIER CA UNIQUEMENT LA PREMIÈRE FOIS
builder: (_) => Text(
'${_.counter}',
),
)
//Initialisez votre contrôleur uniquement la première fois. La deuxième fois que vous utilisez ReBuilder pour le même contrôleur, ne recommencez pas. Votre contrôleur sera automatiquement supprimé de la mémoire dès que le widget qui l'a marqué comme `init` sera déployé. Vous n'avez pas à vous en soucier, Get le fera automatiquement, assurez-vous simplement de ne pas démarrer deux fois le même contrôleur.
```
**Fait!**
- Vous avez déjà appris à gérer les états avec Get.
- Note: Vous pouvez souhaiter une organisation plus grande et ne pas utiliser la propriété init. Pour cela, vous pouvez créer une classe et étendre la classe Bindings, et y mentionner les contrôleurs qui seront créés dans cette route. Les contrôleurs ne seront pas créés à ce moment-là, au contraire, il ne s'agit que d'une déclaration, de sorte que la première fois que vous utilisez un contrôleur, Get saura où chercher. Get restera lazyLoad et continuera à supprimer les contrôleurs lorsqu'ils ne seront plus nécessaires. Voir l'exemple pub.dev pour voir comment cela fonctionne.
Si vous parcourez de nombreuses routes et avez besoin de données qui se trouvaient dans votre contrôleur précédemment utilisé, il vous suffit de réutiliser GetBuilder (sans init):
```dart
class OtherClass extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GetBuilder<Controller>(
builder: (s) => Text('${s.counter}'),
),
),
);
}
```
Si vous devez utiliser votre contrôleur dans de nombreux autres endroits, et en dehors de GetBuilder, créez simplement un get dans votre contrôleur et ayez-le facilement. (ou utilisez `Get.find<Controller>()`)
```dart
class Controller extends GetxController {
/// Vous n'en avez pas besoin. Je recommande de l'utiliser uniquement pour faciliter la syntaxe.
/// avec la méthode statique: Controller.to.counter();
/// sans méthode statique: Get.find<Controller>() .counter();
/// Il n'y a aucune différence de performances, ni aucun effet secondaire de l'utilisation de l'une ou l'autre syntaxe. Un seul n'a pas besoin du type, et l'autre l'EDI le complétera automatiquement.
static Controller get to => Get.find(); // Ajouter cette ligne
int counter = 0;
void increment() {
counter++;
update();
}
}
```
Et puis vous pouvez accéder directement à votre contrôleur, de cette façon:
```dart
FloatingActionButton(
onPressed:() {
Controller.to.increment(),
} // This is incredibly simple!
child: Text("${Controller.to.counter}"),
),
```
Lorsque vous appuyez sur FloatingActionButton, tous les widgets qui écoutent la variable `counter` seront mis à jour automatiquement.
### Comment il gère les contrôleurs
Disons que nous avons ceci:
`Class a => Class B (has controller X) => Class C (has controller X)`
Dans la classe A, le contrôleur n'est pas encore en mémoire, car vous ne l'avez pas encore utilisé (Get est lazyLoad). Dans la classe B, vous avez utilisé le contrôleur et il est entré en mémoire. Dans la classe C, vous avez utilisé le même contrôleur que dans la classe B, Get partagera l'état du contrôleur B avec le contrôleur C, et le même contrôleur est toujours en mémoire. Si vous fermez l'écran C et l'écran B, Get retirera automatiquement le contrôleur X de la mémoire et libèrera des ressources, car la classe A n'utilise pas le contrôleur. Si vous naviguez à nouveau vers B, le contrôleur X entrera à nouveau en mémoire, si au lieu de passer à la classe C, vous revenez en classe A, Get retirera le contrôleur de la mémoire de la même manière. Si la classe C n'utilisait pas le contrôleur et que vous retiriez la classe B de la mémoire, aucune classe n'utiliserait le contrôleur X et de même, elle serait éliminée. La seule exception qui peut gâcher Get, est si vous supprimez B de l'itinéraire de manière inattendue et essayez d'utiliser le contrôleur dans C.Dans ce cas, l'ID de créateur du contrôleur qui était dans B a été supprimé et Get a été programmé pour supprimer de la mémoire tous les contrôleurs qui n'ont pas d'ID de créateur. Si vous avez l'intention de faire cela, ajoutez l'indicateur "autoRemove: false" au GetBuilder de la classe B et utilisez adoptID = true; dans GetBuilder de la classe C.
### Vous n'aurez plus besoin de StatefulWidgets
Utiliser StatefulWidgets signifie stocker inutilement l'état d'écrans entiers, même parce que si vous avez besoin de reconstruire au minimum un widget, vous l'intègrerez dans un Consumer / Observer / BlocProvider / GetBuilder / GetX / Obx, qui sera un autre StatefulWidget.
La classe StatefulWidget est une classe plus grande que StatelessWidget, qui allouera plus de RAM, et cela ne fera peut-être pas une différence significative entre une ou deux classes, mais cela le fera très certainement lorsque vous en aurez 100!
À moins que vous n'ayez besoin d'utiliser un mixin, comme TickerProviderStateMixin, il sera totalement inutile d'utiliser un StatefulWidget avec Get.
Vous pouvez appeler toutes les méthodes d'un StatefulWidget directement à partir d'un GetBuilder.
Si vous devez appeler la méthode initState() ou dispose() par exemple, vous pouvez les appeler directement:
```dart
GetBuilder<Controller>(
initState: (_) => Controller.to.fetchApi(),
dispose: (_) => Controller.to.closeStreams(),
builder: (s) => Text('${s.username}'),
),
```
Une bien meilleure approche que celle-ci consiste à utiliser les méthodes onInit() et onClose() directement à partir de votre contrôleur.
```dart
@override
void onInit() {
fetchApi();
super.onInit();
}
```
- NOTE: Si vous voulez démarrer une méthode au moment où le contrôleur est appelé pour la première fois, vous N'AVEZ PAS BESOIN d'utiliser des constructeurs pour cela, en fait, en utilisant un package orienté performance comme Get, cela frôle la mauvaise pratique, car il s'écarte de la logique dans laquelle les contrôleurs sont créés ou alloués (si vous créez une instance de ce contrôleur, le constructeur sera appelé immédiatement, vous remplirez un contrôleur avant même qu'il ne soit utilisé, vous allouez de la mémoire sans qu'elle ne soit utilisée , cela nuit définitivement aux principes de cette bibliothèque). Les méthodes onInit(); et onClose(); ont été créés pour cela, ils seront appelés lors de la création du Controller, ou lors de sa première utilisation, selon que vous utilisez Get.lazyPut ou non. Si vous voulez, par exemple, faire un appel à votre API pour remplir des données, vous pouvez oublier la méthode à l'ancienne de initState / dispose, lancez simplement votre appel à l'API dans onInit, et si vous devez exécuter une commande comme la fermeture des flux, utilisez onClose() pour cela.
### Pourquoi ca existe
Le but de ce package est précisément de vous donner une solution complète pour la navigation des routes, la gestion des dépendances et des états, en utilisant le moins de dépendances possible, avec un haut degré de découplage. Get engage toutes les API Flutter de haut et bas niveau en lui-même, pour vous assurer de travailler avec le moins de couplage possible. Nous centralisons tout dans un seul package, pour vous assurer que vous n'avez aucun type de couplage dans votre projet. De cette façon, vous pouvez mettre uniquement des widgets dans votre vue et laisser la partie de votre équipe qui travaille avec la `business logique` libre, pour travailler avec la business logique sans dépendre d'aucun élément de la vue. Cela fournit un environnement de travail beaucoup plus propre, de sorte qu'une partie de votre équipe ne travaille qu'avec des widgets, sans se soucier d'envoyer des données à votre contrôleur, et une partie de votre équipe ne travaille qu'avec la business logique dans toute son ampleur, sans dépendre d'aucun élément de la Vue.
Donc, pour simplifier cela:
Vous n'avez pas besoin d'appeler des méthodes dans initState et de les envoyer par paramètre à votre contrôleur, ni d'utiliser votre constructeur de contrôleur pour cela, vous avez la méthode onInit() qui est appelée au bon moment pour démarrer vos services.
Vous n'avez pas besoin d'appeler l'appareil, vous avez la méthode onClose() qui sera appelée au moment exact où votre contrôleur n'est plus nécessaire et sera supprimé de la mémoire. De cette façon, ne laissez les vues que pour les widgets, abstenez-vous d'y mettre tout type de business logique.
N'appelez pas une méthode dispose() dans GetxController, cela ne fera rien, rappelez-vous que le contrôleur n'est pas un Widget, vous ne devez pas le `supprimer`, et il sera automatiquement et intelligemment supprimé de la mémoire par Get. Si vous avez utilisé un Stream et que vous souhaitez le fermer, insérez-le simplement dans la méthode close(). Exemple:
```dart
class Controller extends GetxController {
StreamController<User> user = StreamController<User>();
StreamController<String> name = StreamController<String>();
/// pour fermer stream = méthode onClose(), pas dispose().
@override
void onClose() {
user.close();
name.close();
super.onClose();
}
}
```
Cycle de vie du controlleur:
- onInit() quand il est créé.
- onClose() quand il est fermé pour apporter des modifications en préparation de la méthode delete.
- deleted: vous n'avez pas accès à cette API car elle supprime littéralement le contrôleur de la mémoire. Il est littéralement supprimé, sans laisser de trace.
### Autres formes d utilisation
Vous pouvez utiliser l'instance Controller directement sur la valeur GetBuilder:
```dart
GetBuilder<Controller>(
init: Controller(),
builder: (value) => Text(
'${value.counter}', // ici
),
),
```
Vous pouvez également avoir besoin d'une instance de votre contrôleur en dehors de votre GetBuilder, et vous pouvez utiliser ces approches pour y parvenir:
```dart
class Controller extends GetxController {
static Controller get to => Get.find();
[...]
}
// Dans la vue:
GetBuilder<Controller>(
init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur
builder: (_) => Text(
'${Controller.to.counter}', // ici
)
),
```
ou encore
```dart
class Controller extends GetxController {
// static Controller get to => Get.find(); // sans static get
[...]
}
// Dans la classe stateful/stateless
GetBuilder<Controller>(
init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur
builder: (_) => Text(
'${Get.find<Controller>().counter}', // ici
),
),
```
- Vous pouvez utiliser des approches `non canoniques` pour ce faire. Si vous utilisez un autre gestionnaire de dépendances, comme get_it, modular, etc., et que vous souhaitez simplement fournir l'instance de contrôleur, vous pouvez le faire:
```dart
Controller controller = Controller();
[...]
GetBuilder<Controller>(
init: controller, // ici
builder: (_) => Text(
'${controller.counter}', // ici
),
),
```
### IDs Uniques
Si vous souhaitez affiner le contrôle de mise à jour d'un widget avec GetBuilder, vous pouvez leur attribuer des ID uniques:
```dart
GetBuilder<Controller>(
id: 'text'
init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur
builder: (_) => Text(
'${Get.find<Controller>().counter}', // ici
),
),
```
Et mettez-le à jour de cette façon:
```dart
update(['text']);
```
Vous pouvez également imposer des conditions pour la mise à jour:
```dart
update(['text'], counter < 10);
```
GetX le fait automatiquement et ne reconstruit que le widget qui utilise la variable exacte qui a été modifiée, si vous remplacez une variable par la même que la précédente et que cela n'implique pas un changement d'état, GetX ne reconstruira pas le widget pour économiser de la mémoire et Cycles CPU (3 est affiché à l'écran, et vous changez à nouveau la variable à 3. Dans la plupart des gestionnaires d'états, cela entraînera une nouvelle reconstruction, mais avec GetX, le widget ne sera reconstruit qu'à nouveau, si en fait son état a changé ).
## Mélanger les deux gestionnaires d'état
Certaines personnes ont ouvert une demande de fonctionnalité, car elles ne voulaient utiliser qu'un seul type de variable réactive, et les autres mécanismes, et devaient insérer un Obx dans un GetBuilder pour cela. En y réfléchissant, MixinBuilder a été créé. Il permet à la fois des changements réactifs en changeant les variables ".obs" et des mises à jour mécaniques via update(). Cependant, des 4 widgets c'est celui qui consomme le plus de ressources, car en plus d'avoir un Abonnement pour recevoir les événements de changement de ses enfants, il souscrit à la méthode de mise à jour de son contrôleur.
L'extension de GetxController est importante, car ils ont des cycles de vie et peuvent `démarrer` et `terminer` des événements dans leurs méthodes onInit() et onClose(). Vous pouvez utiliser n'importe quelle classe pour cela, mais je vous recommande fortement d'utiliser la classe GetxController pour placer vos variables, qu'elles soient observables ou non.
## GetBuilder vs GetX vs Obx vs MixinBuilder
En une décennie de travail avec la programmation, j'ai pu apprendre de précieuses leçons.
Mon premier contact avec la programmation réactive a été tellement "wow, c'est incroyable" et en fait la programmation réactive est incroyable.
Cependant, elle ne convient pas à toutes les situations. Souvent, il suffit de changer l'état de 2 ou 3 widgets en même temps, ou d'un changement d'état éphémère, auquel cas la programmation réactive n'est pas mauvaise, mais elle n'est pas appropriée.
La programmation réactive a une consommation de RAM plus élevée qui peut être compensée par le flux de travail individuel, ce qui garantira qu'un seul widget est reconstruit et si nécessaire, mais créer une liste avec 80 objets, chacun avec plusieurs flux n'est pas une bonne idée . Ouvrez le 'dart inspect' et vérifiez combien un StreamBuilder consomme, et vous comprendrez ce que j'essaie de vous dire.
Dans cet esprit, j'ai créé le gestionnaire d'état simple. C'est simple, et c'est exactement ce que vous devriez lui demander: mettre à jour l'état par blocs de manière simple et de la manière la plus économique.
GetBuilder est très économique en RAM, et il n'y a guère d'approche plus économique que lui (du moins je ne peux pas en imaginer une, si elle existe, merci de nous le faire savoir).
Cependant, GetBuilder est toujours un gestionnaire d'état mécanique, vous devez appeler update() comme vous auriez besoin d'appeler les notifyListeners() de Provider.
Il y a d'autres situations où la programmation réactive est vraiment intéressante, et ne pas travailler avec elle revient à réinventer la roue. Dans cet esprit, GetX a été créé pour fournir tout ce qui est le plus moderne et le plus avancé dans un gestionnaire d'état. Il met à jour uniquement ce qui est nécessaire et si nécessaire, si vous avez une erreur et envoyez 300 changements d'état simultanément, GetX filtrera et mettra à jour l'écran uniquement si l'état change réellement.
GetX est toujours plus économique que tout autre gestionnaire d'état réactif, mais il consomme un peu plus de RAM que GetBuilder. En y réfléchissant et en visant à maximiser la consommation de ressources, Obx a été créé. Contrairement à GetX et GetBuilder, vous ne pourrez pas initialiser un contrôleur à l'intérieur d'un Obx, c'est juste un widget avec un StreamSubscription qui reçoit les événements de changement de vos widgets enfants, c'est tout. Il est plus économique que GetX, mais perd face à GetBuilder, ce qui était prévisible, car il est réactif, et GetBuilder a l'approche la plus simpliste qui existe, de stocker le hashcode d'un widget et son StateSetter. Avec Obx, vous n'avez pas besoin d'écrire votre type de contrôleur, et vous pouvez entendre le changement de plusieurs contrôleurs différents, mais il doit être initialisé avant, soit en utilisant l'approche d'exemple au début de ce readme, soit en utilisant la classe Bindings.
\ No newline at end of file
... ...
... ... @@ -84,9 +84,9 @@ Anda bisa melakukan lazyload terhadap sebuah dependensi supaya dependensi terseb
Get.lazyPut<ApiMock>(() => ApiMock());
Get.lazyPut<FirebaseAuth>(
() => {
// ... beberapa logic jika diperlukan..
return FirebaseAuth()
() {
// ... beberapa logic jika diperlukan..
return FirebaseAuth();
},
tag: Math.random().toString(),
fenix: true
... ... @@ -322,7 +322,7 @@ getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<ControllerX>(() => ControllerX());
Get.put<Service>(()=> Api());
}),
... ... @@ -330,7 +330,7 @@ getPages: [
GetPage(
name: '/details',
page: () => DetailsView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<DetailsController>(() => DetailsController());
}),
),
... ...
... ... @@ -248,6 +248,21 @@ print(Get.parameters['user']);
// keluaran: 34954
```
atau kirim beberapa parameter seperti ini
```dart
Get.toNamed("/profile/34954?flag=true");
```
Pada layar kedua, ambil data berdasarkan parameter seperti biasanya
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
// keluaran: 34954 true
```
Dan sekarang, yang anda perlu lakukan adalah menggunakan Get.toNamed() untuk bernavigasi ke named route anda, tanpa konteks (anda bisa memanggil route secara langsung dari kelas BLoC atau Controller), dan ketika aplikasi anda di-compile di web, route anda akan muncul di url <3
### Middleware
... ... @@ -315,7 +330,7 @@ class First extends StatelessWidget {
title: Text('Halaman Pertama'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Pindah halaman'),
onPressed: () {
Get.toNamed("/second");
... ... @@ -340,7 +355,7 @@ class Second extends StatelessWidget {
title: Text('Halaman kedua'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Pindah halaman'),
onPressed: () {
Get.toNamed("/third");
... ... @@ -359,7 +374,7 @@ class Third extends StatelessWidget {
title: Text("Halaman ketiga"),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
onPressed: () {
Get.back();
},
... ... @@ -430,7 +445,7 @@ Get.snackbar(
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// FlatButton mainButton,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
... ... @@ -486,12 +501,12 @@ Get.bottomSheet(
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () => {}
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () => {},
onTap: () {},
),
],
),
... ... @@ -520,7 +535,7 @@ Navigator(
title: Text("Main"),
),
body: Center(
child: FlatButton(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // pindah ke halaman bersarang anda menggunakan index
... ...
... ... @@ -80,9 +80,9 @@ Get.put<S>(
Get.lazyPut<ApiMock>(() => ApiMock());
Get.lazyPut<FirebaseAuth>(
() => {
// 어떤 로직이 필요하다면 ...
return FirebaseAuth()
() {
// 어떤 로직이 필요하다면 ...
return FirebaseAuth();
},
tag: Math.random().toString(),
fenix: true
... ... @@ -308,7 +308,7 @@ getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<ControllerX>(() => ControllerX());
Get.put<Service>(()=> Api());
}),
... ... @@ -316,7 +316,7 @@ getPages: [
GetPage(
name: '/details',
page: () => DetailsView(),
binding: BindingsBuilder(() => {
binding: BindingsBuilder(() {
Get.lazyPut<DetailsController>(() => DetailsController());
}),
),
... ...
... ... @@ -246,6 +246,23 @@ print(Get.parameters['user']);
// 출력: 34954
```
또는 이와 같은 여러 매개 변수를 보냅니다.
```dart
Get.toNamed("/profile/34954?flag=true");
```
두 번째 화면에서 일반적으로 매개 변수별로 데이터를 가져옵니다.
```dart
print(Get.parameters['user']);
print(Get.parameters['flag']);
// 출력: 34954 true
```
이제 Get.toNamed()를 사용하여 어떤 context도 없이 명명된 라우트를 탐색하고 (BLoC 또는 Controller 클래스로 부터 직접 라우트를 호출할 수 있음) 앱이 웹으로 컴파일되면 경로는 url에 표시됩니다. <3
### 미들웨어
... ... @@ -313,7 +330,7 @@ class First extends StatelessWidget {
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/second");
... ... @@ -338,7 +355,7 @@ class Second extends StatelessWidget {
title: Text('second Route'),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Get.toNamed("/third");
... ... @@ -357,7 +374,7 @@ class Third extends StatelessWidget {
title: Text("Third Route"),
),
body: Center(
child: RaisedButton(
child: ElevatedButton(
onPressed: () {
Get.back();
},
... ... @@ -428,7 +445,7 @@ Get.snackbar(
// Color leftBarIndicatorColor,
// List<BoxShadow> boxShadows,
// Gradient backgroundGradient,
// FlatButton mainButton,
// TextButton mainButton,
// OnTap onTap,
// bool isDismissible,
// bool showProgressIndicator,
... ... @@ -484,12 +501,12 @@ Get.bottomSheet(
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
onTap: () => {}
onTap: () {}
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Video'),
onTap: () => {},
onTap: () {},
),
],
),
... ... @@ -518,7 +535,7 @@ Navigator(
title: Text("Main"),
),
body: Center(
child: FlatButton(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // index로 중첩된 경로를 탐색
... ...