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

JavaFX可缩放ScrollPane内节点x/y位移动画不生效问题求助

问题根源
  • 你为ScrollPane开启了fitToHeight、fitToWidth属性,这两个属性会强制将ScrollPane的内容节点拉伸适配视口尺寸,和自由缩放、滚动的需求直接冲突。
  • 内容外层嵌套的StackPane默认采用居中对齐规则,当你修改矩形的x/y属性导致group的布局边界变化时,StackPane会持续将group重新居中,直接抵消了矩形的位移动画效果,仅会在边界计算的间隙出现轻微抖动。
  • 代码中冗余的容器嵌套(声明后未使用的VBox)以及手动调用scrollPane.setViewportBounds(groupBounds)的操作,也会干扰ScrollPane正常的布局计算逻辑。
修复方案

按以下步骤修改代码即可同时保留缩放、平移功能,且位移动画正常运行:

  1. 移除ScrollPane的fitToHeight、fitToWidth属性设置
  2. 清理冗余的容器嵌套,移除无用的VBox声明
  3. 删除滚动事件处理中手动设置viewportBounds的代码行

修改后的可运行示例代码如下:

public class TestAnimationInScroll extends Application {

  public static void main(String[] args) {
    launch(args);
  }
  public void start(Stage primaryStage) {
     Rectangle rect = new Rectangle(100, 100, 50, 50);
     rect.setFill(Color.BLUE);
     Group root = new Group();
     root.getChildren().add(rect);

     Group group = new Group(root);
     StackPane content = new StackPane(group);
     group.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
        content.setMinWidth(newBounds.getWidth());
        content.setMinHeight(newBounds.getHeight());
     });
     ScrollPane scrollPane = new ScrollPane(content);
     scrollPane.setPannable(true);
     scrollPane.setPrefSize(500, 500);

     Timeline timeline = new Timeline();
     KeyFrame kf0 = new KeyFrame(Duration.ZERO, new KeyValue(rect.xProperty(), 0));
     KeyFrame kf1 = new KeyFrame(Duration.seconds(10), new KeyValue(rect.xProperty(), 100));
     timeline.getKeyFrames().addAll(kf0, kf1);
     timeline.play();

     content.setOnScroll(event -> {
        double zoomFactor = 1.05;
        double deltaY = event.getDeltaY();
        if (deltaY < 0) {
           zoomFactor = 1 / zoomFactor;
        }
        Bounds groupBounds = group.getBoundsInLocal();
        final Bounds viewportBounds = scrollPane.getViewportBounds();

        double valX = scrollPane.getHvalue() * (groupBounds.getWidth() - viewportBounds.getWidth());
        double valY = scrollPane.getVvalue() * (groupBounds.getHeight() - viewportBounds.getHeight());
        group.setScaleX(group.getScaleX() * zoomFactor);
        group.setScaleY(group.getScaleY() * zoomFactor);

        Point2D posInZoomTarget = group.parentToLocal(new Point2D(event.getX(), event.getY()));
        Point2D adjustment = group.getLocalToParentTransform().deltaTransform(posInZoomTarget.multiply(zoomFactor - 1));
        scrollPane.layout();

        groupBounds = group.getBoundsInLocal();
        scrollPane.setHvalue((valX + adjustment.getX()) / (groupBounds.getWidth() - viewportBounds.getWidth()));
        scrollPane.setVvalue((valY + adjustment.getY()) / (groupBounds.getHeight() - viewportBounds.getHeight()));
     });

     Scene scene = new Scene(scrollPane, 800, 600);
     primaryStage.setScene(scene);
     primaryStage.show();
  }
}

内容的提问来源于stack exchange,提问作者Hervé Girod

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 21:15:08