Langues: Français (Ce fichier), Anglais, Indonésien, Urdu, Chinois, Portuguais du Brésil, Espagnol, Russe, Polonais, Koréen.
- A Propos de Get
- Installation
- L'application 'Counter' avec GetX
- Les trois pilliers
-
Utils
- Internationalization
- Traductions
- Locales
- Changer le Thème
- GetConnect
- Configuration par défaut
- Configuration personnalisée
- Middleware GetPage
- Priority
- Redirect
- onPageCalled
- OnBindingsStart
- OnPageBuildStart
- OnPageBuilt
- OnPageDispose
- Autres APIs
- Paramètres globaux et configurations manuelles facultatifs
- State Widgets Locaux
- Useful tips
- GetView
- GetResponsiveView
- GetWidget
- GetxService
- Breaking changes from 2.0
- Why Getx?
- Community
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.
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.
De plus, pour augmenter encore votre productivité, nous avons l'extension pour VSCode et l'extension pour Android Studio/Intellij
Installation
Ajoutez Get à votre fichier pubspec.yaml:
dependencies:
get:
Importez Get dans les fichiers dans lesquels il doit être utilisé:
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
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".
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.
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: RaisedButton(
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:
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:
var name = 'Jonatas Borges';
Pour la rendre observable, il vous suffit d'ajouter ".obs" à la fin:
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:
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. 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
GetMaterialApp( // Avant: MaterialApp(
home: MyHome(),
)
Accédez à un nouvel écran:
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
Get.toNamed('/details');
Pour fermer des snackbars, dialogs, bottomsheets, ou tout ce que vous auriez normalement fermé avec Navigator.pop(context);
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.)
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)
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
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:
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.
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:
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:
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
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
.
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
.
Text('title'.tr);
Utiliser les traductions avec le singulier et le pluriel
var products = [];
Text('cléAuSingulier'.trPlural('cléAuPluriel', products.length, Args));
Utiliser les traductions avec paramètres
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.
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.
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
.
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:
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':
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.
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.
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.
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.
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.
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.
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.
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
// 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:
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
Vous pourrez également utiliser votre propre middleware dans GetObserver
, cela n'influencera rien.
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
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:
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.
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
, 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?
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:
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...
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 gettercontroller
pour un Controller
enregistré, c'est tout.
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
You have two options to build it.
- with
builder
method you return the widget to build. - with methods
desktop
,tablet
,phone
,watch
. the specific method will be built when the screen type matches the method when the screen is [ScreenType.Tablet] thetablet
method will be exuded and so on. Note: If you use this method please set the propertyalwaysUseBuilder
tofalse
With settings
property you can set the width limit for the screen types.
Code to this screen
code
GetWidget
Most people have no idea about this Widget, or totally confuse the usage of it.
The use case is very rare, but very specific: It caches
a Controller.
Because of the cache, can't be a const Stateless
.
So, when do you need to "cache" a Controller?
If you use, another "not so common" feature of GetX: Get.create()
.
Get.create(()=>Controller())
will generate a new Controller
each time you call
Get.find<Controller>()
,
That's where GetWidget
shines... as you can use it, for example,
to keep a list of Todo items. So, if the widget gets "rebuilt", it will keep the same controller instance.
GetxService
This class is like a GetxController
, it shares the same lifecycle ( onInit()
, onReady()
, onClose()
).
But has no "logic" inside of it. It just notifies GetX Dependency Injection system, that this subclass
can not be removed from memory.
So is super useful to keep your "Services" always reachable and active with Get.find()
. Like:
ApiService
, StorageService
, CacheService
.
Future<void> main() async {
await initServices(); /// AWAIT SERVICES INITIALIZATION.
runApp(SomeApp());
}
/// Is a smart move to make your Services intiialize before you run the Flutter app.
/// as you can control the execution flow (maybe you need to load some Theme configuration,
/// apiKey, language defined by the User... so load SettingService before running ApiService.
/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.
void initServices() async {
print('starting services ...');
/// Here is where you put get_storage, hive, shared_pref initialization.
/// or moor connection, or whatever that's async.
await Get.putAsync(() => DbService().init());
await Get.putAsync(SettingsService()).init();
print('All services started...');
}
class DbService extends GetxService {
Future<DbService> init() async {
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
class SettingsService extends GetxService {
void init() async {
print('$runtimeType delays 1 sec');
await 1.delay();
print('$runtimeType ready!');
}
}
The only way to actually delete a GetxService
, is with Get.reset()
which is like a
"Hot Reboot" of your app. So remember, if you need absolute persistence of a class instance during the
lifetime of your app, use GetxService
.
Breaking changes from 2.0
1- Rx types:
Before | After |
---|---|
StringX | RxString |
IntX | RxInt |
MapX | RxMap |
ListX | RxList |
NumX | RxNum |
DoubleX | RxDouble |
RxController and GetBuilder now have merged, you no longer need to memorize which controller you want to use, just use GetxController, it will work for simple state management and for reactive as well.
2- NamedRoutes Before:
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
Now:
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => Home()),
]
)
Why this change? Often, it may be necessary to decide which page will be displayed from a parameter, or a login token, the previous approach was inflexible, as it did not allow this. Inserting the page into a function has significantly reduced the RAM consumption, since the routes will not be allocated in memory since the app was started, and it also allowed to do this type of approach:
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
Why Getx?
1- Many times after a Flutter update, many of your packages will break. Sometimes compilation errors happen, errors often appear that there are still no answers about, and the developer needs to know where the error came from, track the error, only then try to open an issue in the corresponding repository, and see its problem solved. Get centralizes the main resources for development (State, dependency and route management), allowing you to add a single package to your pubspec, and start working. After a Flutter update, the only thing you need to do is update the Get dependency, and get to work. Get also resolves compatibility issues. How many times a version of a package is not compatible with the version of another, because one uses a dependency in one version, and the other in another version? This is also not a concern using Get, as everything is in the same package and is fully compatible.
2- Flutter is easy, Flutter is incredible, but Flutter still has some boilerplate that may be unwanted for most developers, such as Navigator.of(context).push (context, builder [...]
. Get simplifies development. Instead of writing 8 lines of code to just call a route, you can just do it: Get.to(Home())
and you're done, you'll go to the next page. Dynamic web urls are a really painful thing to do with Flutter currently, and that with GetX is stupidly simple. Managing states in Flutter, and managing dependencies is also something that generates a lot of discussion, as there are hundreds of patterns in the pub. But there is nothing as easy as adding a ".obs" at the end of your variable, and place your widget inside an Obx, and that's it, all updates to that variable will be automatically updated on the screen.
3- Ease without worrying about performance. Flutter's performance is already amazing, but imagine that you use a state manager, and a locator to distribute your blocs/stores/controllers/ etc. classes. You will have to manually call the exclusion of that dependency when you don't need it. But have you ever thought of simply using your controller, and when it was no longer being used by anyone, it would simply be deleted from memory? That's what GetX does. With SmartManagement, everything that is not being used is deleted from memory, and you shouldn't have to worry about anything but programming. You will be assured that you are consuming the minimum necessary resources, without even having created a logic for this.
4- Actual decoupling. You may have heard the concept "separate the view from the business logic". This is not a peculiarity of BLoC, MVC, MVVM, and any other standard on the market has this concept. However, this concept can often be mitigated in Flutter due to the use of context. If you need context to find an InheritedWidget, you need it in the view, or pass the context by parameter. I particularly find this solution very ugly, and to work in teams we will always have a dependence on View's business logic. Getx is unorthodox with the standard approach, and while it does not completely ban the use of StatefulWidgets, InitState, etc., it always has a similar approach that can be cleaner. Controllers have life cycles, and when you need to make an APIREST request for example, you don't depend on anything in the view. You can use onInit to initiate the http call, and when the data arrives, the variables will be populated. As GetX is fully reactive (really, and works under streams), once the items are filled, all widgets that use that variable will be automatically updated in the view. This allows people with UI expertise to work only with widgets, and not have to send anything to business logic other than user events (like clicking a button), while people working with business logic will be free to create and test the business logic separately.
This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.
Community
Community channels
GetX has a highly active and helpful community. If you have questions, or would like any assistance regarding the use of this framework, please join our community channels, your question will be answered more quickly, and it will be the most suitable place. This repository is exclusive for opening issues, and requesting resources, but feel free to be part of GetX Community.
Slack | Discord | Telegram |
---|---|---|
How to contribute
Want to contribute to the project? We will be proud to highlight you as one of our collaborators. Here are some points where you can contribute and make Get (and Flutter) even better.
- Helping to translate the readme into other languages.
- Adding documentation to the readme (a lot of Get's functions haven't been documented yet).
- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki).
- Offering PRs for code/tests.
- Including new functions.
Any contribution is welcome!
Articles and videos
- Dynamic Themes in 3 lines using GetX™ - Tutorial by Rod Brown.
- Complete GetX™ Navigation - Route management video by Amateur Coder.
- Complete GetX State Management - State management video by Amateur Coder.
- GetX™ Other Features - Utils, storage, bindings and other features video by Amateur Coder.
- Firestore User with GetX | Todo App - Video by Amateur Coder.
- Firebase Auth with GetX | Todo App - Video by Amateur Coder.
- The Flutter GetX™ Ecosystem ~ State Management - State management by Aachman Garg.
- The Flutter GetX™ Ecosystem ~ Dependency Injection - Dependency Injection by Aachman Garg.
- GetX, the all-in-one Flutter package - A brief tutorial covering State Management and Navigation by Thad Carnevalli.
- Build a To-do List App from scratch using Flutter and GetX - UI + State Management + Storage video by Thad Carnevalli.
- GetX Flutter Firebase Auth Example - Article by Jeff McMorris.
- Flutter State Management with GetX – Complete App - by App With Flutter.
- Flutter Routing with Animation using Get Package - by App With Flutter.