如何实现JavaFX自定义Shape从Pane中心向外的填充动画
JavaFX实现从Pane中心向外填充通用Shape的动画
我用JavaFX的Path创建了自定义Shape,想要在指定时间内实现从Pane中心向外扩散的填充动画。目前已经实现了矩形从底部填充的简单版本,但这套逻辑没法适配通用Shape,也做不到从中心向外填充的效果。
当前效果:从Shape底部向上填充
目标效果:从Pane中心点向外扩散填充
解决方案思路
原来的平移矩形遮罩只适合线性方向的填充,要实现通用Shape的中心向外填充,改用圆形遮罩缩放动画+裁剪的方案:
- 准备两个同形状的图形:一个作为轮廓(透明填充、描边),一个作为填充图形(纯色填充)。
- 给填充图形添加圆形遮罩,初始半径极小(仅中心一点),通过动画将遮罩半径放大到能完全覆盖整个Shape的尺寸。
- 计算Shape的边界范围,确定遮罩需要的最大半径,确保动画结束时完全覆盖目标Shape。
完整代码示例
package com.example.javafx21; import javafx.animation.ScaleTransition; import javafx.application.Application; import javafx.geometry.Bounds; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Path; import javafx.scene.shape.PathElement; import javafx.scene.shape.MoveTo; import javafx.scene.shape.LineTo; import javafx.stage.Stage; import javafx.util.Duration; public class HelloApplication extends Application { @Override public void start(Stage primaryStage) { Pane pane = new Pane(); pane.setPrefSize(300, 300); // 自定义Path形状(示例:五角星,可替换为任意自定义Shape) Path outlineShape = createStarShape(150, 150, 50); outlineShape.setStroke(Color.BLACK); outlineShape.setFill(Color.TRANSPARENT); // 填充用的同形状图形 Path fillShape = createStarShape(150, 150, 50); fillShape.setFill(Color.BLUE); // 获取Shape边界,计算遮罩最大半径(中心到最远边界的距离) Bounds shapeBounds = outlineShape.getBoundsInParent(); double centerX = shapeBounds.getCenterX(); double centerY = shapeBounds.getCenterY(); double maxRadius = Math.max( Math.max(centerX - shapeBounds.getMinX(), shapeBounds.getMaxX() - centerX), Math.max(centerY - shapeBounds.getMinY(), shapeBounds.getMaxY() - centerY) ); // 创建圆形遮罩,初始半径为0(仅中心一点) Circle mask = new Circle(centerX, centerY, 0); mask.setFill(Color.WHITE); fillShape.setClip(mask); pane.getChildren().addAll(fillShape, outlineShape); Button button = new Button("开始填充"); button.setLayoutX(120); button.setLayoutY(250); pane.getChildren().add(button); // 缩放动画:2秒内将遮罩从中心小点放大到覆盖整个Shape ScaleTransition fillTransition = new ScaleTransition(Duration.seconds(2), mask); fillTransition.setFromX(0); fillTransition.setFromY(0); fillTransition.setToX(maxRadius / mask.getRadius()); fillTransition.setToY(maxRadius / mask.getRadius()); fillTransition.setCycleCount(1); fillTransition.setAutoReverse(false); button.setOnAction(e -> fillTransition.play()); Scene scene = new Scene(pane); primaryStage.setTitle("中心向外填充动画"); primaryStage.setScene(scene); primaryStage.show(); } // 生成五角星Path的工具方法,可替换为自定义Path逻辑 private Path createStarShape(double centerX, double centerY, double radius) { Path path = new Path(); double angle = Math.PI / 5; for (int i = 0; i < 10; i++) { double r = (i % 2 == 0) ? radius : radius / 2; double x = centerX + r * Math.cos(i * angle - Math.PI / 2); double y = centerY + r * Math.sin(i * angle - Math.PI / 2); PathElement element = (i == 0) ? new MoveTo(x, y) : new LineTo(x, y); path.getElements().add(element); } path.getElements().add(new LineTo(centerX + radius * Math.cos(-Math.PI / 2), centerY + radius * Math.sin(-Math.PI / 2))); return path; } public static void main(String[] args) { launch(args); } }
代码说明
createStarShape方法是示例自定义Shape生成逻辑,你可以直接替换成自己的Path或任意Shape实现。- 通过
getBoundsInParent()获取Shape的边界范围,计算出中心到最远边缘的距离,确保遮罩放大后能完全覆盖目标Shape。 - 使用
ScaleTransition实现遮罩的平滑缩放,若需要自定义动画曲线(如缓入缓出),可以改用Timeline直接动画Circle的radiusProperty()。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

