查找TranslateTransition的两个节点之间的距离

时间:2015-08-25 23:59:53

标签: java animation javafx translate-animation

在我的程序中,我希望对象显示它们从一个点移动到另一个点。我使用了TranslateTransition。为了使它工作,我需要给它一个起始位置,在我的例子中,是到起始节点的距离。

enter image description here

问题是,两个节点位于不同的容器中,因此在计算中使用layoutXlayoutY将无效。

在下面的代码中,我使用localToScene方法将相对于本地节点的坐标转换为场景。然后我做了一点减法来得到两个节点之间相对于移动节点的距离。

import com.neonorb.commons.log.Log;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Node;
import javafx.scene.Parent;
import sun.reflect.generics.reflectiveObjects.LazyReflectiveObjectGenerator;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
 * Created by chris on 8/23/15.
 */
public class TranslateUtils {
    public static DoubleProperty getTranslateX(Node translatingNode, Node otherNode) {
        DoubleProperty ret = new SimpleDoubleProperty();
        Platform.runLater(() -> {
            List<Observable> dependencies = getAllParents(translatingNode).stream().map(Node::layoutXProperty).collect(Collectors.toList());
            dependencies.addAll(getAllParents(otherNode).stream().map(Node::layoutXProperty).collect(Collectors.toList()));
            ret.bind(Bindings.createDoubleBinding(new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    Log.debug("recalculating x");
                    return otherNode.localToScene(otherNode.getBoundsInLocal()).getMinX() - translatingNode.localToScene(translatingNode.getBoundsInLocal()).getMinX();
                }
            }, dependencies.toArray(new Observable[dependencies.size()])));
        });
        return ret;
    }

    public static DoubleProperty getTranslateY(Node translatingNode, Node otherNode) {
        DoubleProperty ret = new SimpleDoubleProperty();
        Platform.runLater(() -> {
            List<Observable> dependencies = getAllParents(translatingNode).stream().map(Node::layoutXProperty).collect(Collectors.toList());
            dependencies.addAll(getAllParents(otherNode).stream().map(Node::layoutXProperty).collect(Collectors.toList()));
            ret.bind(Bindings.createDoubleBinding(new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    Log.debug("recalculating y");
                    return otherNode.localToScene(otherNode.getBoundsInLocal()).getMinY() - translatingNode.localToScene(translatingNode.getBoundsInLocal()).getMinY();
                }
            }, dependencies.toArray(new Observable[dependencies.size()])));
        });
        return ret;
    }

    private static List<Parent> getAllParents(Node node) {
        List<Parent> parents = new ArrayList<Parent>();
        Parent parent = node.getParent();
        if (parent != null) {
            parents.addAll(getAllParents(parent));
            parents.add(parent);
        }
        return parents;
    }
}

您可以使用以下方法测试代码:

import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.controlsfx.tools.Borders;

import java.io.IOException;

/**
 * Created by chris on 7/20/15.
 */
public class Test extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws IOException {
        BorderPane borderPane = new BorderPane();
        Label translatingNode = new Label("translating node");
        HBox translatingHBox = new HBox(translatingNode);
        translatingHBox.setAlignment(Pos.CENTER);
        borderPane.setTop(translatingHBox);
        Label referenceNode = new Label("reference node");
        HBox referenceHBox = new HBox(referenceNode);
        referenceHBox.setAlignment(Pos.CENTER_RIGHT);
        borderPane.setBottom(referenceHBox);
        TranslateTransition translateTransition = new TranslateTransition(Duration.seconds(3), translatingNode);
        translateTransition.fromXProperty().bind(TranslateUtils.getTranslateX(translatingNode, referenceNode));
        translateTransition.fromYProperty().bind(TranslateUtils.getTranslateY(translatingNode, referenceNode));
        translateTransition.setToX(0);
        translateTransition.setToY(0);
        Button playButton = new Button("play");
        playButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                translateTransition.play();
            }
        });
        borderPane.setCenter(playButton);
        primaryStage.setScene(new Scene(borderPane));
        primaryStage.show();
    }
}

您可以第一次成功播放动画,但请尝试调整窗口大小。翻译地点不会更新。

2 个答案:

答案 0 :(得分:1)

您未包含layoutXProperty本身的translatingNode。要修复您的演示,只需将Node本身包含在其父项列表中:

private static List<Node> getAllParents(Node node) {
    List<Node> parents = new ArrayList<Node>();
    if (node != null) {
        parents.addAll(getAllParents(node.getParent()));
        parents.add(node);
    }
    return parents;
}

答案 1 :(得分:0)

我最终使用自定义方法来查找全球位置:

private static double getGlobalX(Node node) {
    if (node == null) {
        return 0.0;
    }
    double parentGlobalX = getGlobalX(node.getParent());
    return node.getLayoutX() - parentGlobalX;
}

private static double getGlobalY(Node node) {
    if (node == null) {
        return 0.0;
    }
    double parentGlobalY = getGlobalY(node.getParent());
    return parentGlobalY - node.getLayoutY();
}