Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
554 views
in Technique[技术] by (71.8m points)

java - JavaFX Marquee Animation

You maybe have seen some apps that when the String in a tab can't be fully shown then it is animated and is going back and front so the user can see what String the tab contains.Android is doing that is settings when your phone display is not enough to show the the whole label.

Below is a code to achieve it in JavaFX using Service,but it is not a good way.

The Question is: Here is how i can do it using Animation or another build in JavaFX class?

Code:

import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import tools.InfoTool;

public class MoveTitleService extends Service<Void>{
    private String title;
    volatile boolean doAnimation;
    private int counter;
    public Label movingText = new Label("A reallyyy big teeeeexxxxxxxxxxxxxxxxxxxxxxxt");


    /**
     *Constructor
    */
    public MoveTitleService() {
         movingText.setFont(Font.font("null",FontWeight.BOLD,14));
         movingText.setTextFill(Color.WHITE);   

         setOnSucceeded( s ->{
             movingText.setText("");
         });
    }

    //Start the Service
    public void startTheService(String title) {
        this.title = title;
        doAnimation = true;

        restart();
    }


    //Stop the Service
    public void stopService(){
        doAnimation=false;
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {

                while (doAnimation) {
                    //System.out.println("MoveTitleService is Running...");

                    // One letter at a time
                    for (int m = 0; m <= title.length(); m++) {
                        counter=m;

                        Platform.runLater( () ->{
                            movingText.setText(title.substring(0, counter) + addSpaces(title.length() - counter));      
                        });

                        if(!doAnimation) break;
                        Thread.sleep(150);
                    }

                    // Disappearing to back
                    for (int m = 0; m < title.length(); m++) {
                        counter=m;

                        Platform.runLater( () ->{
                            movingText.setText(title.substring(counter));
                        });

                        if(!doAnimation) break;
                        Thread.sleep(150);
                    }

                    // Appearing to front
                    for (int m = 1; m <= title.length(); m++) {
                        counter=m;

                        Platform.runLater( () ->{
                            movingText.setText(title.substring(title.length() - counter));
                        });

                        if(!doAnimation) break;
                        Thread.sleep(150);
                    }

                    if(!doAnimation) break;
                    for(int i=0; i<3000/150; i++)
                        Thread.sleep(150);
                    Thread.sleep(3000);

                }

                return null;
            }

            private String addSpaces(int spaces) {
                String z = "";
                for (int i = 0; i <= spaces; i++)
                    z += " ";

                return z;
            }

        };
    }

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could use a Timeline for this:

// min distance to Pane bounds
private static final double OFFSET = 25;

@Override
public void start(Stage primaryStage) {
    Text text = new Text("A reallyyy big teeeeexxxxxxxxxxxxxxxxxxxxxxxt!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    text.setLayoutY(25);
    text.setManaged(false);
    text.setLayoutX(OFFSET);

    Pane pane = new Pane(text);
    pane.setMinHeight(50);

    Timeline timeline = new Timeline();

    KeyFrame updateFrame = new KeyFrame(Duration.seconds(1 / 60d), new EventHandler<ActionEvent>() {

        private boolean rightMovement;

        @Override
        public void handle(ActionEvent event) {
            double tW = text.getLayoutBounds().getWidth();
            double pW = pane.getWidth();
            double layoutX = text.getLayoutX();

            if (2 * OFFSET + tW <= pW && layoutX >= OFFSET) {
                // stop, if the pane is large enough and the position is correct
                text.setLayoutX(OFFSET);
                timeline.stop();
            } else {
                if ((rightMovement && layoutX >= OFFSET) || (!rightMovement && layoutX + tW + OFFSET <= pW)) {
                    // invert movement, if bounds are reached
                    rightMovement = !rightMovement;
                }

                // update position
                if (rightMovement) {
                    layoutX += 1;
                } else {
                    layoutX -= 1;
                }
                text.setLayoutX(layoutX);
            }
        }
    });

    timeline.getKeyFrames().add(updateFrame);
    timeline.setCycleCount(Animation.INDEFINITE);

    // listen to bound changes of the elements to start/stop the animation
    InvalidationListener listener = o -> {
        double textWidth = text.getLayoutBounds().getWidth();
        double paneWidth = pane.getWidth();
        if (textWidth + 2 * OFFSET > paneWidth
                && timeline.getStatus() != Animation.Status.RUNNING) {
            timeline.play();
        }
    };

    text.layoutBoundsProperty().addListener(listener);
    pane.widthProperty().addListener(listener);

    Scene scene = new Scene(pane);

    primaryStage.setScene(scene);
    primaryStage.show();
}

Note that repeadedly updating the position yourself needs to be done, since Animations cannot be adjusted while running, so for any resizing to take effect during the animation, you need repeated updates...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...