Button
Introduction
Nylo Website fournit une classe Button avec huit styles de boutons preconstruits. Chaque bouton offre un support integre pour :
- Etats de chargement asynchrones -- retournez un
FuturedepuisonPressedet le bouton affiche automatiquement un indicateur de chargement - Styles d'animation -- choisissez parmi les effets clickable, bounce, pulse, squeeze, jelly, shine, ripple, morph et shake
- Styles de splash -- ajoutez un retour tactile ripple, highlight, glow ou ink
- Soumission de formulaire -- connectez un bouton directement a une instance
NyFormData
Vous trouverez les definitions des boutons de votre application dans lib/resources/widgets/buttons/buttons.dart. Ce fichier contient une classe Button avec des methodes statiques pour chaque type de bouton, facilitant la personnalisation des valeurs par defaut de votre projet.
Utilisation de base
Utilisez la classe Button n'importe ou dans vos widgets. Voici un exemple simple dans une page :
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Button.primary(
text: "Sign Up",
onPressed: () {
routeTo(SignUpPage.path);
},
),
SizedBox(height: 12),
Button.secondary(
text: "Learn More",
onPressed: () {
routeTo(AboutPage.path);
},
),
SizedBox(height: 12),
Button.outlined(
text: "Cancel",
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
),
);
}
Chaque type de bouton suit le meme schema -- passez un label text et un callback onPressed.
Types de boutons disponibles
Tous les boutons sont accessibles via la classe Button en utilisant des methodes statiques.
Primary
Un bouton rempli avec une ombre, utilisant la couleur primaire de votre theme. Ideal pour les elements d'appel a l'action principaux.
Button.primary(
text: "Sign Up",
onPressed: () {
// Handle press
},
)
Secondary
Un bouton rempli avec une couleur de surface plus douce et une ombre subtile. Adapte aux actions secondaires a cote d'un bouton primaire.
Button.secondary(
text: "Learn More",
onPressed: () {
// Handle press
},
)
Outlined
Un bouton transparent avec une bordure. Utile pour les actions moins prominentes ou les boutons d'annulation.
Button.outlined(
text: "Cancel",
onPressed: () {
// Handle press
},
)
Vous pouvez personnaliser les couleurs de la bordure et du texte :
Button.outlined(
text: "Custom Outline",
borderColor: Colors.red,
textColor: Colors.red,
onPressed: () {},
)
Text Only
Un bouton minimal sans fond ni bordure. Ideal pour les actions en ligne ou les liens.
Button.textOnly(
text: "Skip",
onPressed: () {
// Handle press
},
)
Vous pouvez personnaliser la couleur du texte :
Button.textOnly(
text: "View Details",
textColor: Colors.blue,
onPressed: () {},
)
Icon
Un bouton rempli qui affiche une icone a cote du texte. L'icone apparait avant le texte par defaut.
Button.icon(
text: "Add to Cart",
icon: Icon(Icons.shopping_cart),
onPressed: () {
// Handle press
},
)
Vous pouvez personnaliser la couleur d'arriere-plan :
Button.icon(
text: "Download",
icon: Icon(Icons.download),
color: Colors.green,
onPressed: () {},
)
Gradient
Un bouton avec un fond en degrade lineaire. Utilise par defaut les couleurs primaire et tertiaire de votre theme.
Button.gradient(
text: "Get Started",
onPressed: () {
// Handle press
},
)
Vous pouvez fournir des couleurs de degrade personnalisees :
Button.gradient(
text: "Premium",
gradientColors: [Colors.purple, Colors.pink],
onPressed: () {},
)
Rounded
Un bouton en forme de pilule avec des coins entierement arrondis. Le rayon de bordure est par defaut la moitie de la hauteur du bouton.
Button.rounded(
text: "Continue",
onPressed: () {
// Handle press
},
)
Vous pouvez personnaliser la couleur d'arriere-plan et le rayon de bordure :
Button.rounded(
text: "Apply",
backgroundColor: Colors.teal,
borderRadius: BorderRadius.circular(20),
onPressed: () {},
)
Transparency
Un bouton style verre depoli avec un effet de flou en arriere-plan. Fonctionne bien lorsqu'il est place sur des images ou des fonds colores.
Button.transparency(
text: "Explore",
onPressed: () {
// Handle press
},
)
Vous pouvez personnaliser la couleur du texte :
Button.transparency(
text: "View More",
color: Colors.white,
onPressed: () {},
)
Etat de chargement asynchrone
L'une des fonctionnalites les plus puissantes des boutons Nylo Website est la gestion automatique de l'etat de chargement. Lorsque votre callback onPressed retourne un Future, le bouton affiche automatiquement un indicateur de chargement et desactive l'interaction jusqu'a ce que l'operation soit terminee.
Button.primary(
text: "Submit",
onPressed: () async {
await sleep(3); // Simulates a 3 second async task
},
)
Pendant l'operation asynchrone, le bouton affiche un effet de chargement skeleton (par defaut). Une fois le Future termine, le bouton revient a son etat normal.
Cela fonctionne avec toute operation asynchrone -- appels API, ecritures en base de donnees, telechargements de fichiers ou tout ce qui retourne un Future :
Button.primary(
text: "Save Profile",
onPressed: () async {
await api<ApiService>((request) =>
request.updateProfile(name: "John", email: "john@example.com")
);
showToastSuccess(description: "Profile saved!");
},
)
Button.secondary(
text: "Sync Data",
onPressed: () async {
await fetchAndStoreData();
await clearOldCache();
},
)
Pas besoin de gerer des variables d'etat isLoading, d'appeler setState ou d'envelopper quoi que ce soit dans un StatefulWidget -- Nylo Website gere tout pour vous.
Fonctionnement
Lorsque le bouton detecte que onPressed retourne un Future, il utilise le mecanisme lockRelease pour :
- Afficher un indicateur de chargement (controle par
LoadingStyle) - Desactiver le bouton pour empecher les taps en double
- Attendre la completion du
Future - Restaurer le bouton a son etat normal
Styles d'animation
Les boutons supportent les animations de pression via ButtonAnimationStyle. Ces animations fournissent un retour visuel lorsqu'un utilisateur interagit avec un bouton. Vous pouvez definir le style d'animation lors de la personnalisation de vos boutons dans lib/resources/widgets/buttons/buttons.dart.
Clickable
Un effet de pression 3D style Duolingo. Le bouton se translate vers le bas lors de la pression et rebondit au relachement. Ideal pour les actions principales et les UX ludiques.
animationStyle: ButtonAnimationStyle.clickable()
Ajuster l'effet :
ButtonAnimationStyle.clickable(
translateY: 6.0, // How far the button moves down (default: 4.0)
shadowOffset: 6.0, // Shadow depth (default: 4.0)
duration: Duration(milliseconds: 100),
enableHapticFeedback: true,
)
Bounce
Reduit l'echelle du bouton lors de la pression et rebondit au relachement. Ideal pour les boutons d'ajout au panier, like et favoris.
animationStyle: ButtonAnimationStyle.bounce()
Ajuster l'effet :
ButtonAnimationStyle.bounce(
scaleMin: 0.90, // Minimum scale on press (default: 0.92)
duration: Duration(milliseconds: 150),
curve: Curves.easeOutBack,
enableHapticFeedback: true,
)
Pulse
Une pulsation d'echelle continue et subtile pendant que le bouton est maintenu. Ideal pour les actions de pression longue ou pour attirer l'attention.
animationStyle: ButtonAnimationStyle.pulse()
Ajuster l'effet :
ButtonAnimationStyle.pulse(
pulseScale: 1.08, // Max scale during pulse (default: 1.05)
duration: Duration(milliseconds: 800),
curve: Curves.easeInOut,
)
Squeeze
Compresse le bouton horizontalement et l'etend verticalement lors de la pression. Ideal pour les interfaces ludiques et interactives.
animationStyle: ButtonAnimationStyle.squeeze()
Ajuster l'effet :
ButtonAnimationStyle.squeeze(
squeezeX: 0.93, // Horizontal scale (default: 0.95)
squeezeY: 1.07, // Vertical scale (default: 1.05)
duration: Duration(milliseconds: 120),
enableHapticFeedback: true,
)
Jelly
Un effet de deformation elastique ondulante. Ideal pour les applications ludiques, decontractees ou de divertissement.
animationStyle: ButtonAnimationStyle.jelly()
Ajuster l'effet :
ButtonAnimationStyle.jelly(
jellyStrength: 0.2, // Wobble intensity (default: 0.15)
duration: Duration(milliseconds: 300),
curve: Curves.elasticOut,
enableHapticFeedback: true,
)
Shine
Un reflet brillant qui balaie le bouton lors de la pression. Ideal pour les fonctionnalites premium ou les CTA que vous souhaitez mettre en avant.
animationStyle: ButtonAnimationStyle.shine()
Ajuster l'effet :
ButtonAnimationStyle.shine(
shineColor: Colors.white, // Color of the shine streak (default: white)
shineWidth: 0.4, // Width of the shine band (default: 0.3)
duration: Duration(milliseconds: 600),
)
Ripple
Un effet de vague ameliore qui s'etend depuis le point de contact. Ideal pour l'accentuation Material Design.
animationStyle: ButtonAnimationStyle.ripple()
Ajuster l'effet :
ButtonAnimationStyle.ripple(
rippleScale: 2.5, // How far the ripple expands (default: 2.0)
duration: Duration(milliseconds: 400),
curve: Curves.easeOut,
enableHapticFeedback: true,
)
Morph
Le rayon de bordure du bouton augmente lors de la pression, creant un effet de changement de forme. Ideal pour un retour subtil et elegant.
animationStyle: ButtonAnimationStyle.morph()
Ajuster l'effet :
ButtonAnimationStyle.morph(
morphRadius: 30.0, // Target border radius on press (default: 24.0)
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut,
)
Shake
Une animation de secousse horizontale. Ideal pour les etats d'erreur ou les actions invalides -- secouez le bouton pour signaler que quelque chose s'est mal passe.
animationStyle: ButtonAnimationStyle.shake()
Ajuster l'effet :
ButtonAnimationStyle.shake(
shakeOffset: 10.0, // Horizontal displacement (default: 8.0)
shakeCount: 4, // Number of shakes (default: 3)
duration: Duration(milliseconds: 400),
enableHapticFeedback: true,
)
Desactiver les animations
Pour utiliser un bouton sans animation :
animationStyle: ButtonAnimationStyle.none()
Changer l'animation par defaut
Pour changer l'animation par defaut d'un type de bouton, modifiez votre fichier lib/resources/widgets/buttons/buttons.dart :
class Button {
static Widget primary({
required String text,
VoidCallback? onPressed,
...
}) {
return PrimaryButton(
text: text,
onPressed: onPressed,
animationStyle: ButtonAnimationStyle.bounce(), // Change the default
);
}
}
Styles de splash
Les effets de splash fournissent un retour tactile visuel sur les boutons. Configurez-les via ButtonSplashStyle. Les styles de splash peuvent etre combines avec les styles d'animation pour un retour en couches.
Styles de splash disponibles
| Splash | Factory | Description |
|---|---|---|
| Ripple | ButtonSplashStyle.ripple() |
Ripple Material standard depuis le point de contact |
| Highlight | ButtonSplashStyle.highlight() |
Mise en surbrillance subtile sans animation de ripple |
| Glow | ButtonSplashStyle.glow() |
Lueur douce irradiant depuis le point de contact |
| Ink | ButtonSplashStyle.ink() |
Eclaboussure d'encre rapide, plus rapide et reactive |
| None | ButtonSplashStyle.none() |
Aucun effet de splash |
| Custom | ButtonSplashStyle.custom() |
Controle total sur la factory de splash |
Exemple
class Button {
static Widget outlined({
required String text,
VoidCallback? onPressed,
...
}) {
return OutlinedButton(
text: text,
onPressed: onPressed,
splashStyle: ButtonSplashStyle.ripple(),
animationStyle: ButtonAnimationStyle.clickable(),
);
}
}
Vous pouvez personnaliser les couleurs et l'opacite du splash :
ButtonSplashStyle.ripple(
splashColor: Colors.blue,
highlightColor: Colors.blue,
splashOpacity: 0.2,
highlightOpacity: 0.1,
)
Styles de chargement
L'indicateur de chargement affiche pendant les operations asynchrones est controle par LoadingStyle. Vous pouvez le definir par type de bouton dans votre fichier de boutons.
Skeletonizer (par defaut)
Affiche un effet skeleton shimmer sur le bouton :
loadingStyle: LoadingStyle.skeletonizer()
Normal
Affiche un widget de chargement (par defaut le loader de l'application) :
loadingStyle: LoadingStyle.normal(
child: Text("Please wait..."),
)
None
Garde le bouton visible mais desactive l'interaction pendant le chargement :
loadingStyle: LoadingStyle.none()
Soumission de formulaire
Tous les boutons supportent le parametre submitForm, qui connecte le bouton a un NyForm. Lorsqu'il est touche, le bouton valide le formulaire et appelle votre gestionnaire de succes avec les donnees du formulaire.
Button.primary(
text: "Submit",
submitForm: (LoginForm(), (data) {
// data contains the validated form fields
print(data);
}),
onFailure: (error) {
// Handle validation errors
print(error);
},
)
Le parametre submitForm accepte un record avec deux valeurs :
- Une instance
NyFormData(ou un nom de formulaire commeString) - Un callback qui recoit les donnees validees
Par defaut, showToastError est true, ce qui affiche une notification toast lorsque la validation du formulaire echoue. Definissez-le a false pour gerer les erreurs silencieusement :
Button.primary(
text: "Login",
submitForm: (LoginForm(), (data) async {
await api<AuthApiService>((request) => request.login(data));
}),
showToastError: false,
onFailure: (error) {
// Custom error handling
},
)
Lorsque le callback submitForm retourne un Future, le bouton affiche automatiquement un etat de chargement jusqu'a ce que l'operation asynchrone soit terminee.
Personnaliser les boutons
Toutes les valeurs par defaut des boutons sont definies dans votre projet a lib/resources/widgets/buttons/buttons.dart. Chaque type de bouton a une classe widget correspondante dans lib/resources/widgets/buttons/partials/.
Modifier les styles par defaut
Pour modifier l'apparence par defaut d'un bouton, editez la classe Button :
class Button {
static Widget primary({
required String text,
VoidCallback? onPressed,
(dynamic, Function(dynamic data))? submitForm,
Function(dynamic error)? onFailure,
bool showToastError = true,
double? width,
}) {
return PrimaryButton(
text: text,
onPressed: onPressed,
submitForm: submitForm,
onFailure: onFailure,
showToastError: showToastError,
loadingStyle: LoadingStyle.skeletonizer(),
width: width,
height: 52.0,
animationStyle: ButtonAnimationStyle.bounce(),
splashStyle: ButtonSplashStyle.glow(),
);
}
}
Personnaliser un widget de bouton
Pour modifier l'apparence visuelle d'un type de bouton, editez le widget correspondant dans lib/resources/widgets/buttons/partials/. Par exemple, pour modifier le rayon de bordure ou l'ombre du bouton primaire :
// lib/resources/widgets/buttons/partials/primary_button_widget.dart
class PrimaryButton extends StatefulAppButton {
...
@override
Widget buildButton(BuildContext context) {
final theme = Theme.of(context);
final bgColor = backgroundColor ?? theme.colorScheme.primary;
final fgColor = contentColor ?? theme.colorScheme.onPrimary;
return Container(
width: width ?? double.infinity,
height: height,
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(8), // Change the radius
),
child: Center(
child: Text(
text,
style: TextStyle(
color: fgColor,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
}
Creer un nouveau type de bouton
Pour ajouter un nouveau type de bouton :
- Creez un nouveau fichier widget dans
lib/resources/widgets/buttons/partials/etendantStatefulAppButton. - Implementez la methode
buildButton. - Ajoutez une methode statique dans la classe
Button.
// lib/resources/widgets/buttons/partials/danger_button_widget.dart
class DangerButton extends StatefulAppButton {
DangerButton({
required super.text,
super.onPressed,
super.submitForm,
super.onFailure,
super.showToastError,
super.loadingStyle,
super.width,
super.height,
super.animationStyle,
super.splashStyle,
});
@override
Widget buildButton(BuildContext context) {
return Container(
width: width ?? double.infinity,
height: height,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(14),
),
child: Center(
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
}
Puis enregistrez-le dans la classe Button :
class Button {
...
static Widget danger({
required String text,
VoidCallback? onPressed,
(dynamic, Function(dynamic data))? submitForm,
Function(dynamic error)? onFailure,
bool showToastError = true,
double? width,
}) {
return DangerButton(
text: text,
onPressed: onPressed,
submitForm: submitForm,
onFailure: onFailure,
showToastError: showToastError,
loadingStyle: LoadingStyle.skeletonizer(),
width: width,
height: 52.0,
animationStyle: ButtonAnimationStyle.shake(),
);
}
}
Reference des parametres
Parametres communs (tous les types de boutons)
| Parametre | Type | Defaut | Description |
|---|---|---|---|
text |
String |
requis | Le texte du label du bouton |
onPressed |
VoidCallback? |
null |
Callback lorsque le bouton est touche. Retournez un Future pour un etat de chargement automatique |
submitForm |
(dynamic, Function(dynamic))? |
null |
Record de soumission de formulaire (instance de formulaire, callback de succes) |
onFailure |
Function(dynamic)? |
null |
Appele lorsque la validation du formulaire echoue |
showToastError |
bool |
true |
Afficher une notification toast lors d'une erreur de validation |
width |
double? |
null |
Largeur du bouton (pleine largeur par defaut) |
Parametres specifiques au type
Button.outlined
| Parametre | Type | Defaut | Description |
|---|---|---|---|
borderColor |
Color? |
Couleur de bordure du theme | Couleur de la bordure |
textColor |
Color? |
Couleur primaire du theme | Couleur du texte |
Button.textOnly
| Parametre | Type | Defaut | Description |
|---|---|---|---|
textColor |
Color? |
Couleur primaire du theme | Couleur du texte |
Button.icon
| Parametre | Type | Defaut | Description |
|---|---|---|---|
icon |
Widget |
requis | Le widget d'icone a afficher |
color |
Color? |
Couleur primaire du theme | Couleur d'arriere-plan |
Button.gradient
| Parametre | Type | Defaut | Description |
|---|---|---|---|
gradientColors |
List<Color>? |
Couleurs primaire et tertiaire | Points d'arret du degrade |
Button.rounded
| Parametre | Type | Defaut | Description |
|---|---|---|---|
backgroundColor |
Color? |
Couleur primary container du theme | Couleur d'arriere-plan |
borderRadius |
BorderRadius? |
Forme pilule (hauteur / 2) | Rayon des coins |
Button.transparency
| Parametre | Type | Defaut | Description |
|---|---|---|---|
color |
Color? |
Adaptatif au theme | Couleur du texte |
Parametres ButtonAnimationStyle
| Parametre | Type | Defaut | Description |
|---|---|---|---|
duration |
Duration |
Varie par type | Duree de l'animation |
curve |
Curve |
Varie par type | Courbe de l'animation |
enableHapticFeedback |
bool |
Varie par type | Declencher un retour haptique a la pression |
translateY |
double |
4.0 |
Clickable : distance de pression verticale |
shadowOffset |
double |
4.0 |
Clickable : profondeur de l'ombre |
scaleMin |
double |
0.92 |
Bounce : echelle minimale a la pression |
pulseScale |
double |
1.05 |
Pulse : echelle maximale pendant la pulsation |
squeezeX |
double |
0.95 |
Squeeze : compression horizontale |
squeezeY |
double |
1.05 |
Squeeze : expansion verticale |
jellyStrength |
double |
0.15 |
Jelly : intensite de l'oscillation |
shineColor |
Color |
Colors.white |
Shine : couleur du reflet |
shineWidth |
double |
0.3 |
Shine : largeur de la bande de brillance |
rippleScale |
double |
2.0 |
Ripple : echelle d'expansion |
morphRadius |
double |
24.0 |
Morph : rayon de bordure cible |
shakeOffset |
double |
8.0 |
Shake : deplacement horizontal |
shakeCount |
int |
3 |
Shake : nombre d'oscillations |
Parametres ButtonSplashStyle
| Parametre | Type | Defaut | Description |
|---|---|---|---|
splashColor |
Color? |
Couleur de surface du theme | Couleur de l'effet splash |
highlightColor |
Color? |
Couleur de surface du theme | Couleur de l'effet highlight |
splashOpacity |
double |
0.12 |
Opacite du splash |
highlightOpacity |
double |
0.06 |
Opacite du highlight |
borderRadius |
BorderRadius? |
null |
Rayon de clip du splash |