JavaFX如何保持动画运行,即使下一个动画即将开始?

huangapple go评论51阅读模式
英文:

JavaFx how to keep animation running even if next animation is coming in?

问题

I have created an animation where prompt text will move up as text to the top of its text field when the field is focused, and move downwards when out of focus. However, if the user clicks too fast ( like keep pressing 'tab'), then the animation will the position of the prompt text will go chaos. How do i fix it?

我已经创建了一个动画其中提示文本在字段获得焦点时会向上移动移到文本字段的顶部而在失去焦点时则向下移动然而如果用户点击得太快比如不断按 'tab'),那么动画会使提示文本的位置混乱如何修复它
英文:

I have created an animation where prompt text will move up as text to the top of its text field when the field is focused, and move downwards when out of focus. However, if the user clicks too fast ( like keep pressing 'tab'), then the animation will the position of the prompt text will go chaos. How do i fix it?

import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.util.Duration;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

public class Sing_Up implements Initializable {

    @FXML
    private TextField textField1;
    @FXML
    private TextField textField2;
    @FXML
    private TextField textField3;
    @FXML
    private TextField textField4;
    @FXML
    GridPane d;
    @FXML
    Button button;
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        button.setOnAction(event -> {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Home.fxml"));
            try {
                button.getScene().setRoot(loader.load());
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        for (Node node : d.getChildren()) {
            System.out.println(node);
            // check if the node is a TextField
            if (node instanceof TextField) {
                TextField textField = (TextField) node;
                // apply the animate() method to the TextField
                animate(textField);
            }
    }}

    public void animate(TextField textField){

        Text promptText;
        String p=textField.getPromptText();
        // Create a new Text node to represent the prompt text
        promptText = new Text(textField.getPromptText());
        promptText.setFill(Color.RED);
        promptText.setFont(textField.getFont());
        GridPane parent = (GridPane) textField.getParent();
        GridPane.getRowIndex(textField1);
      
        // Animate the prompt text when the TextField receives focus
        textField.focusedProperty().addListener((observable, oldValue, newValue) -> {

            // Position the prompt text just above the TextField

            if(!parent.getChildren().contains(promptText)&& !(GridPane.getRowIndex(textField) ==null)){
            parent.add(promptText,0, GridPane.getRowIndex(textField));}

            promptText.setVisible(true);
                    if (newValue&&textField.getText().equals("")) {
                        promptText.setVisible(true);
                        TranslateTransition tt = new TranslateTransition(Duration.seconds(0.3), promptText);
                        tt.setByY(-35);
                        tt.play();
                    } else {
                        if (!newValue && textField.getText().isEmpty()){
                            TranslateTransition tt = new TranslateTransition(Duration.seconds(0.3), promptText);
                            tt.setByY (35);
                            tt.play();
                            tt.setOnFinished(event -> {
                                promptText.setVisible(false);

                            });};
;
    }
    ;});}}

答案1

得分: 4

以下是您要翻译的内容:

"While you can consider all the other suggestions in the comments, below is my version of addressing this issue.

Personally I would prefer to create a custom control that can handle this automatically irrespective of its Parent. Currently your logic seems to assume that the TextField is always in a GridPane.

I am considering the usage of Timeline rather than TranslateTransition, because of the fact that I only need the 'end value' for using Timeline. But with TranslateTransition, you need to provide the 'by' value or the 'from/to' values to run the transition (which is the reason it is getting messed up in your case).

Below is the demo of the custom TextField that demonstrates the behavior when rendered in different Parent nodes (here VBox & GridPane)

If you want to show the promptText animation conditionally, change the logic of the isPromptNeeded() method."

接下来是代码部分,不会进行翻译。

英文:

While you can consider all the other suggestions in the comments, below is my version of addressing this issue.

Personally I would prefer to create a custom control that can handle this automatically irrespective of its Parent. Currently your logic seems to assume that the TextField is always in a GridPane.

I am considering the usage of Timeline rather than TranslateTransition, because of the fact that I only need the 'end value' for using Timeline. But with TranslateTransition, you need to provide the 'by' value or the 'from/to' values to run the transition (which is the reason it is getting messed up in your case).

Below is the demo of the custom TextField that demonstrates the behavior when rendered in different Parent nodes (here VBox & GridPane)

If you want to show the promptText animation conditionally, change the logic of the isPromptNeeded() method.

JavaFX如何保持动画运行,即使下一个动画即将开始?

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PromptTextFieldDemo extends Application {

    @Override
    public void start(final Stage stage) throws Exception {
        VBox root = new VBox();
        root.setPadding(new Insets(20));
        root.setSpacing(20);

        /* Add some fields in the GridPane */
        GridPane detailsGrid = new GridPane();
        detailsGrid.setHgap(20);
        detailsGrid.setVgap(20);
        detailsGrid.addRow(0, getField("First Name"), getField("Last Name"), getField("Age"));
        detailsGrid.addRow(1, getField("City"), getField("Company"));

        /* Add some fields in the VBox */
        root.getChildren().addAll(detailsGrid, getField("Address 1"), getField("Address 2"), getField("Address 3"));

        Scene scene = new Scene(root, 450, 300);
        stage.setScene(scene);
        stage.setTitle("PromptTextField Demo");
        stage.show();
    }

    private PromptTextField getField(String text) {
        PromptTextField textField = new PromptTextField();
        textField.setPromptText(text);
        return textField;
    }

    class PromptTextField extends TextField {
        private Text promptNode;

        private Timeline show;

        private Timeline hide;

        private boolean alwaysPrompt = true;

        public PromptTextField() {
            super();
        }

        public PromptTextField(String text) {
            super(text);
        }

        public void setAlwaysPrompt(final boolean alwaysPrompt) {
            this.alwaysPrompt = alwaysPrompt;
        }

        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            if (getPromptText() != null && !getPromptText().isEmpty() && !getChildren().contains(getPromptNode())) {
                getPromptNode().setText(getPromptText());
                getPromptNode().setFont(getFont());
                getChildren().add(getPromptNode());
            }
        }

        public Text getPromptNode() {
            if (promptNode == null) {
                promptNode = new Text();
                promptNode.setFill(Color.RED);
                promptNode.setFont(getFont());
                promptNode.setVisible(false);
                /* Turn off the managed property, so that you control its position using layoutX/Y only. */
                promptNode.setManaged(false);
                promptNode.setLayoutX(8);
                promptNode.setLayoutY(17);

                focusedProperty().addListener((obs, old, focused) -> {
                    if (getPromptText() != null && !getPromptText().isEmpty()) {
                        if (focused && isPromptNeeded()) {
                            if (hide.getStatus() == Animation.Status.RUNNING) {
                                hide.stop();
                            }
                            promptNode.setVisible(true);
                            show.play();
                        } else if(!focused){
                            if (show.getStatus() == Animation.Status.RUNNING) {
                                show.stop();
                            }
                            hide.play();
                        }
                    }
                });

                final KeyFrame showKeyFrame = new KeyFrame(Duration.millis(300), new KeyValue(promptNode.layoutYProperty(), -5));
                show = new Timeline(showKeyFrame);

                final KeyFrame hideKeyFrame = new KeyFrame(Duration.millis(300), new KeyValue(promptNode.layoutYProperty(), 17));
                hide = new Timeline(hideKeyFrame);
                hide.setOnFinished(e -> promptNode.setVisible(false));
            }
            return promptNode;
        }

        private boolean isPromptNeeded(){
            /* Add your custom logic here: about when to show the prompt text animation */
            return alwaysPrompt || getText()==null || getText().isEmpty();
        }
    }
}

huangapple
  • 本文由 发表于 2023年4月11日 00:48:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75978976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定