JavaFX可缩放ScrollPane内节点x/y位移动画不生效问题求助
问题根源
- 你为ScrollPane开启了
fitToHeight、fitToWidth属性,这两个属性会强制将ScrollPane的内容节点拉伸适配视口尺寸,和自由缩放、滚动的需求直接冲突。 - 内容外层嵌套的StackPane默认采用居中对齐规则,当你修改矩形的x/y属性导致group的布局边界变化时,StackPane会持续将group重新居中,直接抵消了矩形的位移动画效果,仅会在边界计算的间隙出现轻微抖动。
- 代码中冗余的容器嵌套(声明后未使用的VBox)以及手动调用
scrollPane.setViewportBounds(groupBounds)的操作,也会干扰ScrollPane正常的布局计算逻辑。
修复方案
按以下步骤修改代码即可同时保留缩放、平移功能,且位移动画正常运行:
- 移除ScrollPane的
fitToHeight、fitToWidth属性设置 - 清理冗余的容器嵌套,移除无用的VBox声明
- 删除滚动事件处理中手动设置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
相关产品推荐
相关产品推荐

