You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX:如何解决快速切换焦点时提示文本动画混乱问题?

修复JavaFX快速切换焦点时提示文本位置混乱问题

问题根源

快速切换焦点时,旧的TranslateTransition动画还未完成就启动新动画,再加上每次用setByY做相对位移,导致位移值不断叠加,同时动画实例重复创建,最终造成提示文本位置错乱。

修复后的代码

import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
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.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()) {
            if (node instanceof TextField) {
                TextField textField = (TextField) node;
                animate(textField);
            }
        }
    }

    public void animate(TextField textField) {
        Text promptText = new Text(textField.getPromptText());
        promptText.setFill(Color.RED);
        promptText.setFont(textField.getFont());
        GridPane parent = (GridPane) textField.getParent();
        Integer rowIndex = GridPane.getRowIndex(textField);
        
        // 仅初始化添加一次提示文本到父容器
        if (rowIndex != null && !parent.getChildren().contains(promptText)) {
            parent.add(promptText, 0, rowIndex);
            promptText.setTranslateY(0); // 固定初始位置
            promptText.setVisible(false);
        }

        // 每个提示文本绑定唯一动画实例
        TranslateTransition tt = new TranslateTransition(Duration.seconds(0.3), promptText);
        tt.setCycleCount(1);
        tt.setAutoReverse(false);

        textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
            // 输入框有文本时直接隐藏提示
            if (!textField.getText().isEmpty()) {
                promptText.setVisible(false);
                tt.stop();
                return;
            }

            promptText.setVisible(true);
            tt.stop(); // 终止当前动画,避免冲突

            if (newValue) {
                tt.setToY(-35); // 绝对位移到输入框顶部
            } else {
                tt.setToY(0); // 绝对位移回初始位置
                tt.setOnFinished(event -> promptText.setVisible(false));
            }
            tt.playFromStart(); // 从起始点重新播放动画
        });

        // 监听文本变化,非空时隐藏提示
        textField.textProperty().addListener((obs, oldText, newText) -> {
            if (!newText.isEmpty()) {
                promptText.setVisible(false);
                tt.stop();
            } else if (!textField.isFocused()) {
                promptText.setVisible(false);
            }
        });
    }
}

核心修复说明

  • 复用动画实例:每个提示文本只创建一个TranslateTransition,避免重复实例导致的动画冲突。
  • 绝对位移替代相对位移:用setToY直接指定目标位置,彻底解决相对位移叠加的问题。
  • 动画前置终止:每次触发新动画前调用tt.stop(),确保旧动画立刻停止,不会干扰新动画的执行。
  • 文本状态联动:输入框有文本时直接隐藏提示,避免不必要的动画触发,同时监听文本变化同步更新提示状态。

内容的提问来源于stack exchange,提问作者ineedmoney

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:07:01