NyState
Introduction
NyState est une version etendue de la classe State standard de Flutter. Elle fournit des fonctionnalites supplementaires pour aider a gerer l'etat de vos pages et widgets de maniere plus efficace.
Vous pouvez interagir avec l'etat exactement comme vous le feriez avec un etat Flutter normal, mais avec les avantages supplementaires de NyState.
Voyons comment utiliser NyState.
Comment utiliser NyState
Vous pouvez commencer a utiliser cette classe en l'etendant.
Exemple
class _HomePageState extends NyState<HomePage> {
@override
get init => () async {
};
@override
view(BuildContext context) {
return Scaffold(
body: Text("The page loaded")
);
}
La methode init est utilisee pour initialiser l'etat de la page. Vous pouvez utiliser cette methode en mode async ou sans async et en coulisses, elle gerera l'appel asynchrone et affichera un chargeur.
La methode view est utilisee pour afficher l'interface de la page.
Creer un nouveau widget stateful avec NyState
Pour creer un nouveau widget stateful dans Nylo Website, vous pouvez executer la commande ci-dessous.
metro make:stateful_widget ProfileImage
Style de chargement
Vous pouvez utiliser la propriete loadingStyle pour definir le style de chargement de votre page.
Exemple
class _ProfileImageState extends NyState<ProfileImage> {
@override
LoadingStyleType get loadingStyle => LoadingStyleType.normal();
@override
get init => () async {
await sleep(3); // simulate a network call for 3 seconds
};
Le loadingStyle par defaut sera votre Widget de chargement (resources/widgets/loader_widget.dart).
Vous pouvez personnaliser le loadingStyle pour modifier le style de chargement.
Voici un tableau des differents styles de chargement que vous pouvez utiliser : // normal, skeletonizer, none
| Style | Description |
|---|---|
| normal | Style de chargement par defaut |
| skeletonizer | Style de chargement en squelette |
| none | Aucun style de chargement |
Vous pouvez changer le style de chargement comme ceci :
@override
LoadingStyle get loadingStyle => LoadingStyle.normal();
// or
@override
LoadingStyle get loadingStyle => LoadingStyle.skeletonizer();
Si vous souhaitez modifier le Widget de chargement dans l'un des styles, vous pouvez passer un child au LoadingStyle.
@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
child: Center(
child: Text("Loading..."),
),
);
// same for skeletonizer
@override
LoadingStyle get loadingStyle => LoadingStyle.skeletonizer(
child: Container(
child: PageLayoutForSkeletonizer(),
)
);
Maintenant, lorsque l'onglet est en cours de chargement, le texte "Loading..." sera affiche.
Exemple ci-dessous :
class _HomePageState extends NyState<HomePage> {
get init => () async {
await sleep(3); // simulate a network call for 3 seconds
};
@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
child: Center(
child: Text("Loading..."),
),
);
@override
Widget view(BuildContext context) {
return Scaffold(
body: Text("The page loaded")
);
}
...
}
Actions d'etat
Dans Nylo, vous pouvez definir de petites actions dans vos Widgets qui peuvent etre appelees depuis d'autres classes. C'est utile si vous souhaitez mettre a jour l'etat d'un widget depuis une autre classe.
D'abord, vous devez definir vos actions dans votre widget. Cela fonctionne pour NyState et NyPage.
class _MyWidgetState extends NyState<MyWidget> {
@override
get init => () async {
// handle how you want to initialize the state
};
@override
get stateActions => {
"hello_world_in_widget": () {
print('Hello world');
},
"update_user_name": (User user) async {
// Example with data
_userName = user.name;
setState(() {});
},
"show_toast": (String message) async {
showToastSuccess(description: message);
},
};
}
Ensuite, vous pouvez appeler l'action depuis une autre classe en utilisant la methode stateAction.
stateAction('hello_world_in_widget', state: MyWidget.state);
// Another example with data
User user = User(name: "John Doe");
stateAction('update_user_name', state: MyWidget.state, data: user);
// Another example with data
stateAction('show_toast', state: MyWidget.state, data: "Hello world");
Si vous utilisez stateActions avec un NyPage, vous devez utiliser le path de la page.
stateAction('hello_world_in_widget', state: ProfilePage.path);
// Another example with data
User user = User(name: "John Doe");
stateAction('update_user_name', state: ProfilePage.path, data: user);
// Another example with data
stateAction('show_toast', state: ProfilePage.path, data: "Hello world");
Il existe egalement une autre classe appelee StateAction, qui dispose de plusieurs methodes que vous pouvez utiliser pour mettre a jour l'etat de vos widgets.
refreshPage- Rafraichir la page.pop- Retirer la page.showToastSorry- Afficher une notification toast de type sorry.showToastWarning- Afficher une notification toast d'avertissement.showToastInfo- Afficher une notification toast d'information.showToastDanger- Afficher une notification toast de danger.showToastOops- Afficher une notification toast de type oops.showToastSuccess- Afficher une notification toast de succes.showToastCustom- Afficher une notification toast personnalisee.validate- Valider les donnees de votre widget.changeLanguage- Mettre a jour la langue de l'application.confirmAction- Effectuer une action de confirmation.
Exemple
class _UpgradeButtonState extends NyState<UpgradeButton> {
view(BuildContext context) {
return Button.primary(
onPressed: () {
StateAction.showToastSuccess(UpgradePage.state,
description: "You have successfully upgraded your account",
);
},
text: "Upgrade",
);
}
}
Vous pouvez utiliser la classe StateAction pour mettre a jour l'etat de n'importe quelle page/widget dans votre application tant que le widget est gere par un etat.
Helpers
Reboot
Cette methode re-executera la methode init dans votre etat. C'est utile si vous souhaitez rafraichir les donnees de la page.
Exemple
class _HomePageState extends NyState<HomePage> {
List<User> users = [];
@override
get init => () async {
users = await api<ApiService>((request) => request.fetchUsers());
};
@override
Widget view(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Users"),
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
reboot(); // refresh the data
},
)
],
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Text(users[index].firstName);
}
),
);
}
}
Pop
pop - Retirer la page actuelle de la pile.
Exemple
class _HomePageState extends NyState<HomePage> {
popView() {
pop();
}
@override
Widget view(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: popView,
child: Text("Pop current view")
)
);
}
showToast
Afficher une notification toast sur le contexte.
Exemple
class _HomePageState extends NyState<HomePage> {
displayToast() {
showToast(
title: "Hello",
description: "World",
icon: Icons.account_circle,
duration: Duration(seconds: 2),
style: ToastNotificationStyleType.INFO // SUCCESS, INFO, DANGER, WARNING
);
}
@override
Widget view(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: displayToast,
child: Text("Display a toast")
)
);
}
validate
Le helper validate effectue une verification de validation sur les donnees.
Vous pouvez en savoir plus sur le validateur ici.
Exemple
class _HomePageState extends NyState<HomePage> {
TextEditingController _textFieldControllerEmail = TextEditingController();
handleForm() {
String textEmail = _textFieldControllerEmail.text;
validate(rules: {
"email address": [textEmail, "email"]
}, onSuccess: () {
print('passed validation')
});
}
changeLanguage
Vous pouvez appeler changeLanguage pour changer le fichier json /lang utilise sur l'appareil.
En savoir plus sur la localisation ici.
Exemple
class _HomePageState extends NyState<HomePage> {
changeLanguageES() {
await changeLanguage('es');
}
@override
Widget view(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: changeLanguageES,
child: Text("Change Language".tr())
)
);
}
whenEnv
Vous pouvez utiliser whenEnv pour executer une fonction lorsque votre application est dans un certain etat.
Par exemple, votre variable APP_ENV dans votre fichier .env est definie sur 'developing', APP_ENV=developing.
Exemple
class _HomePageState extends NyState<HomePage> {
TextEditingController _textEditingController = TextEditingController();
@override
get init => () {
whenEnv('developing', perform: () {
_textEditingController.text = 'test-email@gmail.com';
});
};
lockRelease
Cette methode verrouillera l'etat apres l'appel d'une fonction, jusqu'a ce que la methode soit terminee, elle permettra a l'utilisateur de faire des requetes subsequentes. Cette methode mettra egalement a jour l'etat, utilisez isLocked pour verifier.
Le meilleur exemple pour illustrer lockRelease est d'imaginer un ecran de connexion ou l'utilisateur appuie sur 'Connexion'. Nous voulons effectuer un appel asynchrone pour connecter l'utilisateur mais nous ne voulons pas que la methode soit appelee plusieurs fois car cela pourrait creer une experience indesirable.
Voici un exemple ci-dessous.
class _LoginPageState extends NyState<LoginPage> {
_login() async {
await lockRelease('login_to_app', perform: () async {
await Future.delayed(Duration(seconds: 4), () {
print('Pretend to login...');
});
});
}
@override
Widget view(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isLocked('login_to_app'))
AppLoader(),
Center(
child: InkWell(
onTap: _login,
child: Text("Login"),
),
)
],
)
);
}
Une fois que vous appuyez sur la methode _login, elle bloquera toute requete subsequente jusqu'a ce que la requete originale soit terminee. Le helper isLocked('login_to_app') est utilise pour verifier si le bouton est verrouille. Dans l'exemple ci-dessus, vous pouvez voir que nous l'utilisons pour determiner quand afficher notre Widget de chargement.
isLocked
Cette methode verifiera si l'etat est verrouille en utilisant le helper lockRelease.
Exemple
class _HomePageState extends NyState<HomePage> {
@override
Widget view(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isLocked('login_to_app'))
AppLoader(),
],
)
);
}
view
La methode view est utilisee pour afficher l'interface de la page.
Exemple
class _HomePageState extends NyState<HomePage> {
@override
Widget view(BuildContext context) {
return Scaffold(
body: Center(
child: Text("My Page")
)
);
}
}
confirmAction
La methode confirmAction affichera une boite de dialogue a l'utilisateur pour confirmer une action.
Cette methode est utile si vous souhaitez que l'utilisateur confirme une action avant de continuer.
Exemple
_logout() {
confirmAction(() {
// logout();
}, title: "Logout of the app?");
}
showToastSuccess
La methode showToastSuccess affichera une notification toast de succes a l'utilisateur.
Exemple
_login() {
...
showToastSuccess(
description: "You have successfully logged in"
);
}
showToastOops
La methode showToastOops affichera une notification toast de type oops a l'utilisateur.
Exemple
_error() {
...
showToastOops(
description: "Something went wrong"
);
}
showToastDanger
La methode showToastDanger affichera une notification toast de danger a l'utilisateur.
Exemple
_error() {
...
showToastDanger(
description: "Something went wrong"
);
}
showToastInfo
La methode showToastInfo affichera une notification toast d'information a l'utilisateur.
Exemple
_info() {
...
showToastInfo(
description: "Your account has been updated"
);
}
showToastWarning
La methode showToastWarning affichera une notification toast d'avertissement a l'utilisateur.
Exemple
_warning() {
...
showToastWarning(
description: "Your account is about to expire"
);
}
showToastSorry
La methode showToastSorry affichera une notification toast de type sorry a l'utilisateur.
Exemple
_sorry() {
...
showToastSorry(
description: "Your account has been suspended"
);
}
isLoading
La methode isLoading verifiera si l'etat est en cours de chargement.
Exemple
class _HomePageState extends NyState<HomePage> {
@override
Widget build(BuildContext context) {
if (isLoading()) {
return AppLoader();
}
return Scaffold(
body: Text("The page loaded", style: TextStyle(
color: colors().primaryContent
)
)
);
}
afterLoad
La methode afterLoad peut etre utilisee pour afficher un chargeur jusqu'a ce que l'etat ait termine le 'chargement'.
Vous pouvez egalement verifier d'autres cles de chargement en utilisant le parametre loadingKey afterLoad(child: () {}, loadingKey: 'home_data').
Exemple
class _HomePageState extends NyState<HomePage> {
@override
get init => () {
awaitData(perform: () async {
await sleep(4);
print('4 seconds after...');
});
};
@override
Widget build(BuildContext context) {
return Scaffold(
body: afterLoad(child: () {
return Text("Loaded");
})
);
}
afterNotLocked
La methode afterNotLocked verifiera si l'etat est verrouille.
Si l'etat est verrouille, elle affichera le widget de [chargement].
Exemple
class _HomePageState extends NyState<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: afterNotLocked('login', child: () {
return MaterialButton(
onPressed: () {
login();
},
child: Text("Login"),
);
}),
)
);
}
login() async {
await lockRelease('login', perform: () async {
await sleep(4);
print('4 seconds after...');
});
}
}
afterNotNull
Vous pouvez utiliser afterNotNull pour afficher un widget de chargement jusqu'a ce qu'une variable ait ete definie.
Imaginez que vous devez recuperer le compte d'un utilisateur depuis une base de donnees en utilisant un appel Future qui pourrait prendre 1 a 2 secondes, vous pouvez utiliser afterNotNull sur cette valeur jusqu'a ce que vous ayez les donnees.
Exemple
class _HomePageState extends NyState<HomePage> {
User? _user;
@override
get init => () async {
_user = await api<ApiService>((request) => request.fetchUser()); // example
setState(() {});
};
@override
Widget build(BuildContext context) {
return Scaffold(
body: afterNotNull(_user, child: () {
return Text(_user!.firstName);
})
);
}
setLoading
Vous pouvez passer a un etat de 'chargement' en utilisant setLoading.
Le premier parametre accepte un bool pour indiquer s'il est en chargement ou non, le parametre suivant vous permet de definir un nom pour l'etat de chargement, par exemple setLoading(true, name: 'refreshing_content');.
Exemple
class _HomePageState extends NyState<HomePage> {
@override
get init => () async {
setLoading(true, name: 'refreshing_content');
await sleep(4);
setLoading(false, name: 'refreshing_content');
};
@override
Widget build(BuildContext context) {
if (isLoading(name: 'refreshing_content')) {
return AppLoader();
}
return Scaffold(
body: Text("The page loaded")
);
}