[Actualit�] Les transitions CSS en JavaFX (partie 1)
par
, 31/10/2024 � 05h31 (7450 Affichages)
Parmi les notes de mises a jour de JavaFX 23 on peut voir l'info suivante qui s'y est gliss�e en catimini :
Envoy� par https://gluonhq.com/products/javafx/openjfx-23-release-notes/#23
Bien que le ticket sur le JDK Bug System date de 2023, on peut trouver des tickets plus anciens datant de 2010 et de 2014 qui demandent essentiellement la meme chose : permettre de d�finir des animations dans les feuilles de style. Autant dire que c��tait une fonctionnalit� simple (d'apparence) mais qui �tait attendue de longue date.Envoy� par https://openjfx.io/highlights/23/
Je ne vais pas m��tendre en long et en large sur les limitations de la syntaxe, des propri�t�s support�es, ni sur les capacit�s � capturer les �v�nements d'animation CSS depuis le code, l'excellent article (en anglais) "CSS Transitions" disponible sur PragmaticCode fait tout cela beaucoup plus en d�tails. L'important est de savoir que, grosso modo, les transitions CSS JavaFX sont inspir�es des transitions CSS pour le web d�finies par par le W3.org.
Placer des transitions (animations) l�g�res dans le fichier CSS permet d'enrichir la pr�sentation visuelle sans devoir alourdir de code du composant. C'est une autre mani�re de s�parer la vue (la presentation) des classes m�tier, tout comme le fait de placer le design des formulaires dans un fichier FXML externe et de se contenter de mettre le code permettant de faire fonctionner ce formulaire dans une classe contr�leur. Ceci dit rien n'oblige � utiliser un FXML pour mettre en oeuvre ces transitions, elle fonctionnent tr�s bien en l��tat sur des �crans d�finis dans du code Java pur (ou Kotlin ou autre) aussi.
Mise en place du projet
Commen�ons donc par �crire un simple programme JavaFX qui contient juste une sc�ne, contenant un gestionnaire de mise en page de type BorderPane (la mise en page peut se faire dans 5 emplacements : haut, bas, droite, gauche et centre) :
Code Java : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package test.csstransition; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public final class Main extends Application { public static void main(final String... args) { launch(args); } @Override public void start(final Stage stage) throws Exception { final var root = new BorderPane(); final var scene = new Scene(root); stage.setTitle("Test"); stage.setWidth(800); stage.setHeight(600); stage.setScene(scene); stage.show(); } }
Nous allons �galement en profiter pour ajouter quelques n�uds graphiques dans note scene : un contr�le, ici un bouton, plusieurs formes g�om�triques et une r�gion. Je rappelle qu'une r�gion est un n�ud graphique repr�sentant g�n�ralement une forme rectangulaire skinnable, et qui sert de base a la plupart des contr�les.
Code Java : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 final var button = new Button("Button"); final var tooBar = new ToolBar(); tooBar.getItems().setAll(button); final var rectangle = new Rectangle(200, 200, 150, 100); rectangle.getStyleClass().add("rectangle"); final var circle = new Circle(100); circle.getStyleClass().add("circle"); circle.setCenterX(150); circle.setCenterY(150); final var region = new Region(); region.getStyleClass().add("region"); region.setLayoutX(300); region.setLayoutY(275); final var center = new Pane(); center.getChildren().setAll(rectangle, circle, region); root.setTop(tooBar); root.setCenter(center);
Pour le moment rien de bien excitant : les 2 formes sont noires (initialisation avec les options par d�faut) et la r�gion est invisible car soit transparent, soit avec la la m�me couleur de fond que celle de notre conteneur parent.
Ajout de la feuille de style
J�ins�re ensuite un fichier de feuille de style CSS vide dans le m�me package, et je charge ce fichier de la mani�re suivante :
Code Java : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3 Optional.ofNullable(getClass().getResource("test.css")) .map(URL::toExternalForm) .ifPresent(scene.getStylesheets()::add);
Et nous allons commencer � remplir le CSS en donnant une apparence un peu plus color�e � notre contenu en ajoutant les lignes suivantes dans le fichier CSS :
* Le cercle sera bleu avec une bordure noire de 1 pixel d��paisseur.
* le rectangle sera rempli d'un gradient vertical allant du bleu au vert et avec une bordure affichant un gradient diagonal allant du jaune vers le rouge avec une �paisseur de 2 pixels.
* la r�gion sera dot�e d'une taille minimale de 100 � 75 pixels, avec un fond rouge et une bordure grise, le tout semi-transparent.
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 .rectangle { -fx-fill: linear-gradient(to bottom, blue, green); -fx-stroke: linear-gradient(to bottom right, yellow, red); -fx-stroke-width: 2px; } .circle { -fx-fill: blue; -fx-stroke: black; -fx-stroke-width: 1px; } .region { -fx-background-color: red; -fx-background-radius: 0px; -fx-border-color: grey; -fx-border-width: 1px; -fx-border-radius: 0px; -fx-min-width: 100px; -fx-min-height: 75px; -fx-opacity: 0.5; }
Ce qui nous donne d�sormais ceci :
Et les transitions ?
Nous y arrivons ! Pour d�clencher une animation, nous avons besoin de 2 choses : premi�rement un �tat diff�rent de l��tat de base. Ceci se s'accomplit g�n�ralement en CSS gr�ce � une ou plusieurs pseudo classe. Ici nous allons utiliser la pseudo-classe hover qui d�note le fait que le curseur de la souris se trouve au-dessus du n�ud cibl�. C'est un des pseudo-classe pr�d�finies et qui se trouvent aussi dans les CSS web, mais ne vous inqui�tez pas, les transitions CSS en JavaFX fonctionnent aussi avec des pseudo-classes personnalis�es.
Et la seconde chose dont nous avons besoin c'est une ou plusieurs propri�t�s que nous allons faire varier. Ici, nous allons prendre par exemple, la propri�t� -fx-rotate de la classe Rectangle. Cette propri�t� d�finit bien s�r l'angle de la rotation qui est appliqu�e sur le n�ud. Notre CSS va donc devenir :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9 .rectangle { -fx-fill: linear-gradient(to bottom, blue, green); -fx-stroke: linear-gradient(to bottom right, yellow, red); -fx-stroke-width: 2px; -fx-rotate: 0; } .rectangle:hover { -fx-rotate: 90; }
Si on relance l'application, on peut voir que le rectangle tourne de 90� sur lui-m�me d�s que le curseur entre dans sa boite englobante. Attention cependant, �vitez de mettre votre curseur trop pr�s du bord droit ou gauche du rectangle si vous souffrez �pilepsie. En effet, dans ce cas le rectangle va basculer tr�s rapidement sans arr�t d'entre son �tat par d�faut et son �tat hover provoquant un clignotement assez d�sagr�able � l'�cran. Cela est d� au fait que, d�s que le rectangle se trouve orient� � 90�, votre curseur est en dehors de la boite englobante, provoquant ainsi un retour � l��tat initial, et ainsi de suite, ad vitam.
Changeons maintenant la d�finition pour rajouter l'animation de la rotation :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10 .rectangle { -fx-fill: linear-gradient(to bottom, blue, green); -fx-stroke: linear-gradient(to bottom right, yellow, red); -fx-stroke-width: 2px; -fx-rotate: 0; transition: -fx-rotate 2s; } .rectangle:hover { -fx-rotate: 90; }
La ligne transition: -fx-rotate 2s; qui est d�finie dans le s�lecteur de base du rectangle permet de d�finir une animation d'une dur�e de 2 secondes sur la propri�t� -fx-rotate permettant ainsi d'avoir une transition fluide entre l'�tat par d�faut et l'�tat hover. Quand le curseur de la souris sort de la boite englobante du n�ud, l'animation commence par se mettre en pause avant de s'inverser pour tenter de revenir � l��tat initial. L'effet est quand m�me plus agr�able que le clignotement pr�c�dent.
Il est aussi possible d��crire cette transition de la mani�re suivante :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8 .rectangle { -fx-fill: linear-gradient(to bottom, blue, green); -fx-stroke: linear-gradient(to bottom right, yellow, red); -fx-stroke-width: 2px; -fx-rotate: 0; transition-property: -fx-rotate; transition-duration: 2s; }
La directive transition et les sous-directives associ�es permettent donc de sp�cifier une ou plusieurs propri�t�, un temps d'animation et �galement un interpolateur. Il est �galement possible de specifier un temps d'attente avant d�marrage de l'animation. De multiples d�finitions d'animations doivent �tre s�par�es par des virgule.
- transition - sp�cifie une ou plusieurs animation de mani�re condens�e. Il est possible d'utiliser le mot-cl� all pour signaler des transitions sur toutes les propri�t�s idoines ;
- transition-property - sp�cifie une ou plusieurs propri�t�s � animer. Il est �galement possible d'utiliser le mot-cl� all ici ;
- transition-duration - sp�cifie une ou plusieurs dur�e d'animation. Le nombre de dur�es doit correspondre au nombre de propri�t�s d�finies ;
- transition-delay - sp�cifie un ou plusieurs d�lais d'attente avant animation. Le nombre de d�lais doit correspondre au nombre de propri�t�s d�finies ;
- transition-timing-function - sp�cifie un ou plusieurs interpolateurs � appliquer � l'animation. Voir Guide de reference des CSS de JavaFX 23. Le nombre d'interpolateurs doit correspondre au nombre de propri�t�s d�finies ;
Prenons maintenant notre cercle, je vais lancer une transition sur sa position, son opacit�, l��paisseur de sa bordure et ses couleurs de remplissages et de trait. Pour faire simple, je vais mettre toutes ses transitions � la m�me dur�e de 3 secondes. Pour la version de base non anim�e cela done :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 .circle { -fx-fill: blue; -fx-stroke: black; -fx-stroke-width: 1px; -fx-opacity: 1.0; -fx-translate-x: 0; -fx-translate-y: 0; } .circle:hover { -fx-fill: cyan; -fx-stroke: yellow; -fx-stroke-width: 50px; -fx-opacity: 0.5; -fx-translate-x: 50; -fx-translate-y: 50; }
Et pour rajouter des transitions, n'importe laquelle de ces d�finitions qui sont �quivalentes fera l'affaire :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2 transition-property: -fx-fill, -fx-stroke, -fx-stroke-width, -fx-translate-x, -fx-translate-y; transition-duration: 3s, 3s, 3s, 3s, 3s;
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part transition: -fx-fill 3s, -fx-stroke 3s, -fx-stroke-width 3s, -fx-translate-x 3s, -fx-translate-y 3s;
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part transition: all 3s;
Limitations
Actuellement, les transitions CSS en JavaFX fonctionnent avec toutes les propri�t�s qui utilisent des valeurs num�riques ou qui impl�mentent l'interface javafx.animation.Interpolatable<T>, ce qui inclut les impl�mentations JavaFX des couleurs (javafx.scene.paint.Color), mais aussi les point 2D (javafx.geometry.Point2D) et les points 3D (javafx.geometry.Point3D). Les couleurs sont utilis�es un peu partout dans les CSS fournies par d�faut, mais je n'ai pas crois� d�occurrence d'utilisation de point 2D ou 3D. Sur le papier, il devrait �tre possible de cr�er des transition avec des propri�t�s customis�es, voir des types interpolables customis�s, mais il n'est pas dit que le moteur CSS de JavaFX soit capable d�inf�rer les bonnes classe lors de la lecture de la feuille de style. � noter que des am�liorations sur le parsing des CSS sont en pr�paration pour les futures version de JavaFX permettant de mieux supporter des types de valeur autres.
Il n'est pas possible de faire des transitions sur les couleurs pr�d�finies. Dans les CSS par d�faut de JavaFX, beaucoup de couleurs sont pr�d�finies ; par exemple -fx-color contient la couleur grise qui est appliqu�e dans la plupart des conteneurs. Et il est possible de red�finir ces couleurs dans des CSS customs :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7 .rectangle { -fx-color: green; -fx-fill: -fx-color; } .rectangle:hover { -fx-color: blue; }
La couleur changera bien du vert au bleu lorsque le curseur entre dans la boite englobante du rectangle mais si on d�finie une transition CSS ciblant -fx-color (au lieu de -fx-fill), celle-ci ne fonctionnera pas et, � l��cran, on conservera la transition abrupte pr�c�dente.
Et en ce qui concerne les contr�les ? En fait c'est l� o� le bas blesse : la plupart des propri�t�s stylables visuelles sur les contr�les sont d�finies dans la classe Region et concernent des choses telles que la bordure et la surface interne du contr�le. Souvent ce sont des propri�t�s qui d�finissent un � plusieurs objets complexes qui ne sont pas interpolables. Donc, dans JavaFX 23, en gros, ce qu'on peut animer sur les contr�les via les transitions CSS ce sont surtout les m�mes propri�t�s d�opacit� ou de taille, positionnement, angle, �chelle, etc. que sur les formes g�om�triques ; et il reste impossible de faire des transitions sur les bordures, leurs �paisseurs et angles de coins arrondis ou encore sur la peinture de fond du contr�le.
Par exemple, en appliquant la feuille de style suivante, tous les changements seront appliqu�s lorsque le curseur passera au-dessus de la r�gion, mais la transition CSS impliquera uniquement l�opacit� de la r�gion :
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 .region { -fx-background-color: red; -fx-background-radius: 0px; -fx-border-color: grey; -fx-border-width: 1px; -fx-border-radius: 0px; -fx-opacity: 0.5; -fx-min-width: 100px; -fx-min-height: 75px; transition: all 2s; } .region:hover { -fx-background-color: purple; -fx-background-radius: 21px; -fx-border-color: black; -fx-border-width: 10px; -fx-border-radius: 20px; -fx-opacity: 1; }
Conclusion
Voici le code et la feuille de style finale pour ce bref aper�u de cette nouvelle fonctionnalit�. Utilis�e avec parcimonie et subtilit�, elle peut permettre de rajouter une touche de zestes et de piments � vos interface graphiques JavaFX sans pour autant devoir se lancer dans de lourds travaux de codages d'animations en Java pur. Il suffira de quelques modifications de vos fichiers CSS !
Code Java : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 package test.csstransition; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ToolBar; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; import java.net.URL; import java.util.Optional; public final class Main extends Application { public static void main(final String... args) { launch(args); } @Override public void start(final Stage stage) throws Exception { // Toolbar & button. final var button = new Button("Button"); final var tooBar = new ToolBar(); tooBar.getItems().setAll(button); // Shapes & region. final var rectangle = new Rectangle(200, 200, 150, 100); rectangle.getStyleClass().add("rectangle"); final var circle = new Circle(100); circle.getStyleClass().add("circle"); circle.setCenterX(150); circle.setCenterY(150); final var region = new Region(); region.getStyleClass().add("region"); region.setLayoutX(300); region.setLayoutY(275); final var center = new Pane(); center.getChildren().setAll(rectangle, circle, region); // Layout. final var root = new BorderPane(); root.setTop(tooBar); root.setCenter(center); final var scene = new Scene(root); // load and apply CSS. Optional.ofNullable(getClass().getResource("test.css")) .map(URL::toExternalForm) .ifPresent(scene.getStylesheets()::add); stage.setTitle("Test"); stage.setWidth(800); stage.setHeight(600); stage.setScene(scene); stage.show(); } }
Code CSS : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 .button { -fx-opacity: 0.5; transition: -fx-opacity 1s; } .button:hover { -fx-opacity: 1.0; } .rectangle { -fx-fill: linear-gradient(to bottom, blue, green); -fx-stroke: linear-gradient(to bottom right, yellow, red); -fx-stroke-width: 2px; -fx-rotate: 0; transition: -fx-rotate 2s; /* transition-property: -fx-rotate;*/ /* transition-duration: 2s;*/ } .rectangle:hover { -fx-rotate: 90; } .circle { -fx-fill: blue; -fx-stroke: black; -fx-stroke-width: 1px; -fx-opacity: 1.0; -fx-translate-x: 0; -fx-translate-y: 0; transition: all 3s; /* transition: -fx-fill 3s, -fx-stroke 3s, -fx-stroke-width 3s, -fx-translate-x 3s, -fx-translate-y 3s;*/ /* transition-property: -fx-fill, -fx-stroke, -fx-stroke-width, -fx-translate-x, -fx-translate-y;*/ /* transition-duration: 3s, 3s, 3s, 3s, 3s;*/ } .circle:hover { -fx-fill: cyan; -fx-stroke: yellow; -fx-stroke-width: 50px; -fx-opacity: 0.5; -fx-translate-x: 50; -fx-translate-y: 50; } .region { -fx-background-color: red; -fx-background-radius: 0px; -fx-border-color: grey; -fx-border-width: 1px; -fx-border-radius: 0px; -fx-opacity: 0.5; -fx-min-width: 100px; -fx-min-height: 75px; transition: all 2s; } .region:hover { -fx-background-color: purple; -fx-background-radius: 21px; -fx-border-color: black; -fx-border-width: 10px; -fx-border-radius: 20px; -fx-opacity: 1; }
�pilogue ?
Vous avez pu remarquer que ce blog post est intitul� "partie 1". En effet, comme nous avons pu le voir, bien que sympathiques sur des formes g�om�triques, les animations CSS ne fonctionnent autant qu'on le voudrait sur des r�gions ou des contr�les car les �l�ments CSS de ces n�uds sont plus complexes et ne sont pas interpolables. Cependant, des am�liorations du support des animations CSS pour ce genre de propri�t�s sont annonc�es pour le futur JavaFX 24 qui devrait pointer le bout de son nez en mars 2025.
� suivre... ?