简体   繁体   中英

JavaFX animation restore to original state

My goal here is to have some animation on a node (such as a fade transition) that serves as a temporary notice that something is happening. I want the animation completely gone, like it never happened when that something has ended.

The code snipped below is an example of the problem I'm having. In the current state, when the button is hit to stop the process the button just stays at it's current opacity. If the commented line is uncommented, the button no longer stays at it's current opacity but updates to look correct. My problem then is that when the button is hit again, the CSS opacity for the default stylesheet (Modena.css for JavaFX 8) is no longer taking effect.

Is there something I'm doing wrong, or is there a better way altogether?

package gui.control.custom;

import javafx.animation.Animation;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Test extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Stage stage = new Stage();
        HBox box = new HBox();

        streamButton = new Button("Start");
        streamButton.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                if (started) {
                    stopProcess();
                } else {
                    startProcess();
                }
            }

        });
        box.getChildren().add(streamButton);
        stage.setScene(new Scene(box));
        stage.show();
    }

    FadeTransition ft;
    Button streamButton;
    boolean started = false;

    private void startProcess() {
        streamButton.setDisable(true);
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ex) {
                }
                Platform.runLater(() -> {
                    started = true;
                    streamButton.setText("Stop");
                    streamButton.setDisable(false);
                    startButtonAnim();
                });
            }
        }.start();
    }

    private void stopProcess() {
        streamButton.setText("Start");
        stopButtonAnim();
        started = false;
    }

    private void startButtonAnim() {
        ft = new FadeTransition(Duration.millis(500), streamButton);
        ft.setFromValue(1.0);
        ft.setToValue(0.3);
        ft.setCycleCount(Animation.INDEFINITE);
        ft.setAutoReverse(true);
        ft.play();
    }

    private void stopButtonAnim() {
        ft.stop();
        //streamButton.setOpacity(1);
    }

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

}

Another idea:

I have found this method in javadoc: getCurrentRate() , which should give you negative result on reversing, so the code would look like this:

private void stopButtonAnim() {
    while(ft.getCurrentRate>=0); //waiting till animation goes (skips if already reversing)
    while(ft.getCurrentRate<=0); //and till reverse
    ft.stop(); //then stop
    streamButton.setOpacity(1); //make it 100% ;)
}

Maybe you have to add Thread.sleep(int) to while cycle

I think the best solution is to use jumpTo(Duration duration) right before you stop the Animation . Setting the duration to Duration.ZERO .

Circle circle2 = new Circle(250, 120, 80);
circle2.setFill(Color.RED);
circle2.setStroke(Color.BLACK);
FadeTransition fade = new FadeTransition();
fade.setDuration(Duration.millis(5000));
fade.setFromValue(10);
fade.setToValue(0.1);
fade.setCycleCount(1000);
fade.setAutoReverse(true);
fade.setNode(circle2);
fade.play();

Button btnStop = new Button("Stop");
btnStop.setOnAction((event) -> {
    fade.jumpTo(Duration.ZERO);
    fade.stop();
});

I would try this insetad of simply stop(); this line

setOnFinished(e->tryToStop());

And create this method as:

public void tryToStop(){
    if(!started)
        fm.stop();
}

stopProcess() method changes the started variable, so it will stop in this two cases:

  1. if it is finished

AND

  1. if it is reqested to stop

Not tested, just an idea

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM