Installation
Ajoutez cubixd à vos dépendances pubspec.yaml
dependencies:
cubixd: ^0.1.1
Et puis importez-le:
import 'package:cubixd/cubixd.dart';
Caractéristiques
- Ajoutez ceci à votre application Flutter pour obtenir un cube 3D !
Commencer
Ce forfait comprend 2 widgets :
- AniméCubixD
- CubixD
AnimatedCubixD est le cube 3d animé, ce widget utilise 3 contrôleurs (AnimationController
) pour 3 animations différentes. Inclut l’ombre, les étoiles colorées, toutes les animations et la fonctionnalité pour sélectionner un champ
CubixD est le cube 3d statique, ce widget inclut la fonctionnalité pour sélectionner un champ (sans l’animation)
L’exemple que vous avez vu au début, vous pouvez le faire avec le code suivant :
import 'package:cubixd/cubixd.dart';
Center(
child: AnimatedCubixD(
onSelected: ((SelectedSide opt) => opt == SelectedSide.bottom ? false : true),
size: 200.0,
left: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/graphql.png"),
fit: BoxFit.cover,
),
),
),
front: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/nestjs.png"),
fit: BoxFit.cover,
),
),
),
back: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/mongodb.png"),
fit: BoxFit.cover,
),
),
),
top: ...,
bottom: ...,
right: ...,
),
),
AniméCubixD
Paramètres
Paramètre | Taper | Valeur par défaut | Description |
---|---|---|---|
avancéXYposAnim | AnimRequirements | – | Animation de position XY avancée. Si vous voulez plus de contrôle sur l’AnimationController et les 2 animations nécessaires, vous pouvez définir ce paramètre. Gardez à l’esprit que l’AnimationController ne transmettra pas et ne supprimera pas automatiquement lorsque vous définissez cette option. Vous pouvez lire plus d’informations et d’exemples ci-dessous |
afterRestDel | Durée | Duration(miliseconds: 50) |
Après le délai de restauration. Ce paramètre représente le délai après l’exécution de l’animation de restauration cubixd pour redevenir l’animation principale |
aprèsSelSuppr | Durée | Duration(seconds: 4) |
Après le délai de sélection. Ce paramètre représente la durée pendant laquelle cubixd attend après la sélection d’un visage, et juste après ce temps, restaure le cubixd à l’animation principale |
arrière * | Widget | – | Le widget qui doit être affiché au verso |
fond * | Widget | – | Le widget qui doit être affiché sur la face inférieure |
buildOnSelect | Fonction Widget (double, AnimationController) | nul | Si vous n’aimez pas l’animation par défaut qui se déclenche lorsque l’utilisateur sélectionne un visage. Avec une grande liberté, vous pouvez en définir un autre avec ce paramètre. Celui-ci est assez complexe, donc vous pouvez en savoir plus à ce sujet ci-dessous |
debounceTime | Durée | Duration(miliseconds: 500) |
Temps de désembuage. Le cubixd fonctionne avec un anti-rebond, cela signifie que lorsque vous déplacez constamment le cubixd pour sélectionner un visage, il n’exécutera pas la sélection tant que vous ne le laisserez pas statique avec un visage valide et attendez la durée spécifiée ici, il déclenchera la sélection, sinon si vous le déplacez juste avant que le temps ne s’écoule, il « rebondira » la sélection et comptera à partir de 0 cette fois spécifié ici |
de face * | Widget | – | Le widget qui doit être affiché sur la face avant |
gauche * | Widget | – | Le widget qui devrait être affiché sur le côté gauche de la face |
onPanUpdate | annuler la fonction () | nul | Sur la mise à jour panoramique. Ceci est un rappel qui exécute tout ce que l’utilisateur déplace le cubixd pour sélectionner un visage |
onRestCurve | Courbe | Curves.fastOutSlowIn |
Sur la courbe de restauration. Ce paramètre définit la courbe qui doit avoir l’animation de restauration. Comprendre l’animation de restauration comme l’animation qui s’exécute après la sélection d’un visage pour restaurer le cubixd à sa position de départ |
onSelecCurve | Courbe | Curves.fastOutSlowIn |
Sur la courbe de sélection. Ce paramètre définit la courbe qui a l’animation de sélection. Comprendre l’animation de sélection comme l’animation qui se déclenche juste au moment où la minuterie anti-rebond se termine et déclenche la sélection |
surSélectionner | booléen Fonction(SelectedSide) | nul | Sur Sélectionner. Le rappel qui doit se déclencher lorsqu’un utilisateur sélectionne un visage |
restDuration | Durée | Duration(miliseconds: 800) |
Durée de restauration. La durée que l’animation de restauration doit prendre |
droit * | Widget | – | Le widget qui devrait être affiché sur le côté droit de la face |
durée de vente | Durée | Duration(miliseconds: 400) |
Sélectionnez Durée. La durée que l’animation de sélection doit prendre. Comprendre l’animation de sélection comme l’animation qui se produit juste après le déclenchement de l’anti-rebond |
sensibilitéFac | double | 1.0 | Facteur de sensibilité. Tout comme une souris a une sensibilité lorsque vous la déplacez. Le cubixd a aussi une sensibilité. Il est idéal que cette valeur soit proche de 1 et non de 0 ou moins. Plus sa valeur est grande, plus la sensibilité sera trop |
ombre | bourdonner | vrai | Ombre. Définit si le cubixd doit avoir une ombre. Gardez à l’esprit que s’il n’y a pas d’ombre, le cubixd ne bougera pas du tout de haut en bas (et la hauteur finale que ce widget prendra sera réduite) |
simplePosAnim | SimpleAnimRequirements | SimpleAnimRequirements(duration: const Duration(seconds: 10), xBegin: -pi / 4, xEnd: (7*pi)/4, yBegin: pi / 4, yEnd: pi / 4, reverseWhenDone: false, infinite: true) |
Si vous ne souhaitez pas définir d’options avancées avec un AnimationController, vous pouvez utiliser ce paramètre pour définir quelques paramètres afin de faire bouger votre cubixd c : Vous pouvez lire plus d’informations sur ce paramètre ci-dessous |
Taille * | double | – | La largeur et la hauteur que chaque face doit avoir |
étoiles | bourdonner | vrai | Si les étoiles colorées doivent apparaître juste après la sélection d’un visage |
Haut * | Widget | – | Le widget qui doit être affiché sur la face supérieure |
surSélectionner
Un cube 3D devrait toujours avoir 6 faces, mais peut-être que vous ne voulez que 5 faces. Vous pourriez avoir 5 faces prêtes à être sélectionnées et 1 hors service. c’est ce que l’on pensait en considérant ce paramètre : un rappel qui envoie le visage qui a été sélectionné, et si ce rappel renvoie faux, ce visage ne peut pas être sélectionné, sinon il peut
AnimatedCubixD(
...
onSelected: (SelectedSide opt) {
switch (opt) {
case SelectedSide.back:
return true;
case SelectedSide.top:
return true;
case SelectedSide.front:
return true;
case SelectedSide.bottom:
return false; // out of service
case SelectedSide.right:
return true;
case SelectedSide.left:
return true;
case SelectedSide.none:
// You can do something else
return false; // Nothing will happend if you return true at this point
default:
throw Exception("Unimplemented option");
}
}
...
),
Si ce paramètre n’est pas défini (null). L’utilisateur ne pourra pas déplacer le cubixd
En conséquence nous obtenons
avancéXYposAnim
AnimRequirements
Paramètre | Taper | Valeur par défaut | Description |
---|---|---|---|
manette * | AnimationContrôleur | – | Le AnimationController qui doit être utilisé sur l’animation principale. Ici, vous pouvez définir la durée de l’animation principale |
xAnimation * | Animation | – | L’animation qui doit être utilisée sur l’axe horizontal. Ici, vous définissez l’angle de départ x et l’angle de fin x (en radians) |
yAnimation * | Animation | – | L’animation qui doit être utilisée sur l’axe vertical. Ici, vous définissez l’angle de départ y et l’angle de fin y (en radians) |
Exemple
...
late final AnimationController _mainCtrl;
late final Animation<double> _xAnimation;
late final Animation<double> _yAnimation;
...
@override
void initState(){
_mainCtrl = AnimationController(vsync: this, duration: const Duration(seconds: 10));
_xAnimation = Tween<double>(begin: -pi / 4, end: pi * 2 - pi / 4).animate(_mainCtrl);
_yAnimation = Tween<double>(begin: pi / 4, end: pi / 4).animate(_mainCtrl);
_mainCtrl.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_mainCtrl.reverse();
} else if (status == AnimationStatus.dismissed) {
_mainCtrl.forward();
}
print(status);
});
_mainCtrl.forward();
super.initState();
}
...
AnimatedCubixD(
...
advancedXYposAnim: AnimRequirements(
controller: _mainCtrl,
xAnimation: _xAnimation,
yAnimation: _yAnimation,
),
...
),
...
@override
void dispose(){
_mainCtrl.dispose();
super.dispose();
}
...
buildOnSelect
C’est probablement le paramètre le plus complexe de tout ce package, je vous recommande donc de lire cette section les fois où vous en aurez besoin
Que faire si vous souhaitez avoir une autre animation de démarrage lorsque vous sélectionnez un visage ? Avec ce paramètre, vous pouvez le faire. Lorsque l’utilisateur sélectionne un visage, une autre animation est en cours d’exécution pour placer le de cubixd sur le visage sélectionné, j’appelle cela « sélectionner l’animation » et cette animation est complètement différente de l’animation principale, c’est pourquoi elle a un autre AnimationController.
AnimatedCubixD utilise 3 contrôleurs différents pour 3 animations différentes :
-
Animation principale. Il utilise le contrôleur que vous pouvez ou non transmettre à AnimatedCubixD depuis
advancedXYposAnim
paramètre, si vous ne lui avez pas du tout passé de contrôleur, il le créera lui-même et exécutera automatiquement les méthodes forward et dispose -
Sélectionnez l’animation. Il crée son contrôleur uniquement si
onSelect
paramètre n’est pas nul. Ceci est utilisé pour exécuter l’animation qui joue pour ajuster les angles exacts du visage sélectionné -
Restaurer l’animation. Il crée son contrôleur uniquement si
onSelect
paramètre n’est pas nul. Ceci est utilisé pour exécuter l’animation qui joue pour ajuster le cubixd à sa position initiale après qu’un visage a été sélectionné par l’utilisateur
Dans cette optique, le callback de ce paramètre envoie 2 arguments : size (double) et le select animation controller (AnimationController
), ce rappel s’attend à ce que vous renvoyiez un widget qui s’affichera juste après que l’utilisateur aura sélectionné un visage
import 'dart:math';
import 'package:cubixd/cubixd.dart';
...
AnimatedCubixD(
...
buildOnSelect: (double size, AnimationController ctrl) => CircleStar(ctrl: ctrl, size: size),
stars: false,
...
),
...
class _Animations {
final Animation<double> xAnim;
final Animation<double> yAnim;
final double size;
_Animations(this.xAnim, this.yAnim, this.size);
}
class CircleStar extends StatelessWidget {
final CurvedAnimation _curvedA;
final double overflowQ = 0.4;
final List<_Animations> _starsA = [];
final List<int> _minMax = [20, 35];
CircleStar({
Key? key,
required AnimationController ctrl,
required double size,
}) : _curvedA = CurvedAnimation(parent: ctrl, curve: Curves.easeOutCubic),
super(key: key) {
_initParams(size);
ctrl.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_initParams(size);
}
});
}
void _initParams(double size) {
_starsA.clear();
final int length = Random().nextInt(_minMax[1] - _minMax[]) + _minMax[];
final double overflow = overflowQ * size;
for (int i = ; i < length; i++) {
final double shapeSize = Random().nextDouble() * size * 0.8;
final double lPos = Random().nextDouble() * size;
final double tPos = Random().nextDouble() * size;
final double xEnd;
final double yEnd;
if (-lPos.abs() % size < -tPos.abs() % size) {
xEnd = lPos > size / 2 ? size + overflow : -overflow;
yEnd = xEnd * (tPos / xEnd);
} else {
yEnd = tPos > size / 2 ? size + overflow : -overflow;
xEnd = yEnd / (tPos / lPos);
}
_starsA.add(_Animations(
Tween<double>(begin: lPos, end: xEnd).animate(_curvedA),
Tween<double>(begin: tPos, end: yEnd).animate(_curvedA),
shapeSize,
));
}
}
List<Widget> get _buildList {
final List<Widget> list = [];
final Color color = Color((Random().nextDouble() * 0xFFFFFF).toInt());
for (int i = ; i < _starsA.length; i++) {
list.add(Positioned(
left: ,
top: ,
child: Transform.translate(
offset: Offset(_starsA[i].xAnim.value, _starsA[i].yAnim.value),
child: Transform.rotate(
angle: -4 * pi * _curvedA.value,
child: ClipPath(
clipper: _CircleStarClip(),
child: Container(
color: color.withOpacity(1 - _curvedA.value),
height: _starsA[i].size,
width: _starsA[i].size,
),
),
),
),
));
}
return list;
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _curvedA,
builder: (_, __) {
return Stack(children: _buildList);
},
);
}
}
class _CircleStarClip extends CustomClipper<Path> {
static const _starShrink = 2;
static const _starSides = 5;
static const _deg90 = pi / 2;
@override
Path getClip(Size size) {
final double bigRad = size.width / 2;
final double centerX = size.width / 2;
final double centerY = size.height / 2;
final double smallRad = bigRad / _starShrink;
const double sides = 2 * pi / _starSides;
final Path path = Path()..moveTo(size.width / 2, );
for (int i = ; i < _starSides + 1; i++) {
path.lineTo(cos(sides * i + _deg90) * bigRad + centerX,
sin(sides * i + _deg90) * bigRad + centerY);
path.lineTo(cos(sides * i + _deg90) * smallRad + centerX,
sin(sides * i + _deg90) * smallRad + centerY);
}
return path..close();
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
...
Astuces:
- Vous pourriez avoir votre animation personnalisée et celle par défaut (les départs) en cours d’exécution ensemble
- Vous pouvez coder votre animation personnalisée avec un
StatefulWidget
à la place d’unStatelessWidget
et utiliser une méthode plus orthodoxe
Voici un ralenti du résultat :
simplePosAnim
Précédemment, nous avons indiqué que la valeur par défaut que prend ce paramètre est :
import 'package:cubixd/cubixd.dart';
...
simplePosAnim: SimpleAnimRequirements(
duration: const Duration(seconds: 10),
infinite: true,
reverseWhenDone: false,
xBegin: -pi / 4,
xEnd: (7*pi)/4,
yBegin: pi / 4,
yEnd: pi / 4,
),
...
cubixd prend ces valeurs comme animation par défaut uniquement si ce paramètre (simplePosAnim) et advancedXYposAnim ne sont pas définis
Un autre exemple
import 'package:cubixd/cubixd.dart';
...
simplePosAnim: SimpleAnimRequirements(
duration: const Duration(seconds: 11),
infinite: true,
reverseWhenDone: true,
xBegin: pi / 4,
xCurve: Curves.ease,
xEnd: 2 * pi,
yBegin: -pi / 4,
yCurve: Curves.ease,
yEnd: 4 * pi,
),
...
SimpleAnimRequirements
Paramètre | Taper | Valeur par défaut | Description |
---|---|---|---|
durée * | Durée | – | La durée que l’animation principale devrait avoir |
infini | bourdonner | vrai | Si l’animation principale doit jouer à l’infini |
reverseWhenDone | bourdonner | faux | Si le cubixd doit jouer à l’envers lorsqu’il se termine |
xDébut * | double | – | L’angle horizontal (en radians) qui doit être défini au début de l’animation |
xCourbe | Courbe | Curves.linear |
La courbe qui devrait avoir l’animation principale sur son axe horizontal |
xFin * | double | – | L’angle horizontal (en radians) qui doit être défini à la fin de l’animation |
yCommencer * | double | – | L’angle vertical (en radians) qui doit être défini au début de l’animation |
yCourbe | Courbe | Curves.linear |
La courbe qui devrait avoir l’animation principale sur son axe vertical |
yFin * | double | – | L’angle vertical (en radians) qui doit être défini à la fin de l’animation |
CubixD
CubixD est le widget qui affiche le cube 3d. L’ombre et l’animation de rotation ne font pas partie de ce widget, mais la sélection d’un visage fait (presque) partie de ce widget, à l’exception de l’animation qui joue pour placer le cubixd à sa position exacte exacte du visage cela ne fait pas partie de ce widget
Paramètres
Paramètre | Taper | Valeur par défaut | Description |
---|---|---|---|
arrière * | Widget | – | Le widget qui doit être affiché au verso |
fond * | Widget | – | Le widget qui doit être affiché sur la face inférieure |
debounceTime | Durée | Duration(milliseconds: 500) |
Temps de désembuage. Le cubixd fonctionne avec un anti-rebond, cela signifie que lorsque vous déplacez constamment le cubixd pour sélectionner un visage, il n’exécutera pas la sélection tant que vous ne le laisserez pas statique avec un visage valide et attendez la durée spécifiée ici, il déclenchera la sélection, sinon si vous le déplacez juste avant que le temps ne s’écoule, il « rebondira » la sélection et comptera à partir de 0 cette fois spécifié ici |
delta * | Vecteur2 | – | L’angle horizontal et vertical (en radians) du cubixd. Vous pouvez en savoir plus à ce sujet ci-dessous |
de face * | Widget | – | Le widget qui doit être affiché sur la face avant |
gauche * | Widget | – | Le widget qui devrait être affiché sur le côté gauche de la face |
onPanUpdate | VideCallback | nul | Sur la mise à jour panoramique. Ceci est un rappel qui exécute tout ce que l’utilisateur déplace le cubixd pour sélectionner un visage |
surSélectionné | void Function (SelectedSide opt, Vector2 delta) | nul | Sur Sélectionné. Le rappel qui doit se déclencher lorsqu’un utilisateur sélectionne un visage |
droit * | Widget | – | Le widget qui devrait être affiché sur le côté droit de la face |
sensibilitéFac | double | 1.0 | Facteur de sensibilité. Tout comme une souris a une sensibilité lorsque vous la déplacez. Le cubixd a aussi une sensibilité. Il est idéal que cette valeur soit proche de 1 et non de 0 ou moins. Plus sa valeur est grande, plus la sensibilité sera trop |
Taille * | double | – | La largeur et la hauteur que chaque face doit avoir |
Haut * | Widget | – | Le widget qui doit être affiché sur la face supérieure |
delta
Ce paramètre représente l’angle horizontal et vertical du cubixd (en radians) AnimatedCubixD utilise ce paramètre avec un AnimatedBuilder pour faire fonctionner l’animation en mettant à jour chaque fois que son contrôleur respectif l’indique
import 'package:vector_math/vector_math_64.dart' show Vector2;
import 'package:cubixd/cubixd.dart';
...
CubixD(
...
delta: Vector2(verticalAngle, horizontalAngle)
...
),
...
Voici un exemple
import 'package:cubixd/cubixd.dart';
...
CubixD(
size: 200.0,
delta: Vector2(pi / 4, pi / 4),
onSelected: (SelectedSide opt, Vector2 delta) {
print('On selected callback:\n\topt = ${opt}\n\tdelta = ${delta}');
},
front: ...,
back: ...,
right: ...,
left: ...,
top: ...,
bottom: ...,
),
...
En conséquence nous obtenons :
Suppléments
Côté sélectionné
SelectedSide c’est une énumération qui aide à savoir quel côté a été sélectionné :
enum SelectedSide { front, back, right, left, top, bottom, none }
Les calculs ne sont pas exacts
Soyez conscient que lorsque vous souhaitez obtenir un angle spécifique. L’angle horizontal « change » la direction en fonction de l’angle vertical, en voici un exemple :
Si l’angle vertical est compris entre -90° et 90°. Un angle horizontal supérieur à 0 (positif) a une direction de droite à gauche.
Sinon, si l’angle vertical est supérieur à 90°. Un angle horizontal supérieur à 0 (positif) a une direction de gauche à droite.
TOUT
-
Il serait peut-être préférable d’attacher les widgets avant, arrière, droite, gauche, haut et bas avec une liste de widgets
List<Widget>
-
Offrir la possibilité de contrôler l’animation de haut en bas
GitHub
Voir Github