user13632019
user13632019

Reputation:

Is there any way to implement this CSS animation in JavaFX?

The html and css code:

I took this code from this post

div {
    position: relative;
    display: inline-block;
    padding: 15px 70px;
    border: 5px solid #B17461;
    color: #B17461;
    font-size: 30px;
    font-family: arial;
    background-image: linear-gradient(#B17461, #B17461);
    background-position: 50% 50%;
    background-repeat: no-repeat;
    background-size: 0% 100%;
    transition: background-size .5s, color .5s;
  }
  div:hover {
    background-size: 100% 100%;
    color: #fff;
  }
<div>NEXT</div>

I want to know whether it's possible to implement this animation in JavaFX? I've tried placing a progress bar behind a button both of which are wrapped in a StackPane. The progress bar has the background color of its .track set to transparent and the button's background color to transparent. But this seems like an inefficient way of doing things and to be honest is quite tedious to implement. So is there any other method more suitable for animating?

Upvotes: 1

Views: 835

Answers (2)

swpalmer
swpalmer

Reputation: 4380

Something like this, or you could modify it to adjust background insets like codeflush.dev's answer...

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        Rectangle rect = new Rectangle(300, 30, Color.web("B17461"));
        rect.setScaleX(0);
        Button button = new Button("A Button");
        StackPane pane = new StackPane(rect, button);
        pane.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));

        TranslateTransition trans = new TranslateTransition(Duration.millis(500), rect);
        trans.setFromX(-150);
        trans.setToX(0);
        ScaleTransition scale = new ScaleTransition(Duration.millis(500), rect);
        scale.setFromX(0);
        scale.setToX(1);
        FillTransition fade = new FillTransition(Duration.millis(500), rect, Color.web("B17461"), Color.WHITE);
        Transition t = new ParallelTransition(trans, scale, fade);

        pane.setOnMouseEntered(me -> {
            t.stop();
            t.setRate(1);
            t.play();
        });
        pane.setOnMouseExited(me -> {
            t.stop();
            t.setRate(-1);
            t.play();
        });

        Scene scene = new Scene(pane);
        stage.setTitle("Transition");
        stage.setScene(scene);
        stage.setMinWidth(300);
        stage.setMinHeight(60);
        stage.show();
    }
}

Upvotes: 1

Felix
Felix

Reputation: 2386

This simple application does pretty much the same as you showed:

package example;

import javafx.animation.Animation;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    public static void main(String[] args) {
        launch(Main.class, args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        final Pane root = new Pane();
        // this color will be used for the Text-Color (not hovered), Border and the Background-Color (on hover)
        final Paint color = Color.web("#B17461");

        // basic stuff: text, font and text-color
        final Label label = new Label("NEXT");
        label.setFont(Font.font("Arial", 50.0));
        label.setTextFill(color);
        label.setTextAlignment(TextAlignment.CENTER);
        // same padding as you had
        label.setPadding(new Insets(15, 70, 15, 70));
        // border with the same settings as you had (5px solid)
        label.setBorder(new Border(new BorderStroke(color, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(5))));

        // maybe there's a better way to do this, but this one is the one I know. Simple Transition-Animation with a cycle of .5s
        // the interpolate-Method will be called by JavaFX on every frame with the current "progress" (from 0.0 to 1.0), so we simply calculate the background size in there
        final Animation animation = new Transition() {
            {
                setCycleDuration(Duration.millis(500L));
            }

            @Override
            protected void interpolate(double progress) {
                final double total = label.getWidth() / 2.0;
                final double current = (1.0 - progress) * total;

                label.setBackground(new Background(new BackgroundFill(color, CornerRadii.EMPTY, new Insets(0.0, current, 0.0, current))));
            }
        };

        // "hover": change text color and start the animation
        label.setOnMouseEntered(event -> {
            label.setTextFill(Color.web("#fff"));
            animation.playFromStart();
        });

        // "unhover": stop animation, reset background and text color
        label.setOnMouseExited(event -> {
            animation.stop();
            label.setBackground(null);
            label.setTextFill(color);
        });

      
        root.getChildren().add(label);

        stage.setScene(new Scene(root));
        stage.sizeToScene();
        stage.show();
    }
}

Basically I just did everything you have in your css programmatically on the label. For the animation, I used a simple Transition combined with the Insets value of the labels background. The Insets describe how much space the background should not fill, it's like a padding but only for the background.

Upvotes: 1

Related Questions