如何在JavaFX启动画面(SplashScreen)中显示动态GIF或视频?
JavaFX SplashScreen 中动态GIF/视频无法播放的解决办法
你遇到的问题根源在于JavaFX应用线程被阻塞了——你在Main类的start方法里调用了Thread.sleep(5000),这个方法会直接卡住负责UI渲染(包括GIF动画帧更新)的应用线程,导致启动画面的GIF完全没法播放,直到sleep结束、主界面加载完成后,线程空闲下来才会开始动。
要解决这个问题,核心思路是把耗时的初始化逻辑(比如你模拟的后端加载)放到后台线程中执行,让JavaFX应用线程能专心处理启动画面的渲染和动画。我们可以用JavaFX自带的Task来实现安全的后台任务,它能自动处理和UI线程的交互。
修改后的代码实现
1. 优化Main类(移除线程阻塞逻辑)
package com.example; import javafx.application.Application; import javafx.application.Preloader.StateChangeNotification; import javafx.concurrent.Task; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class Main extends Application{ Stage stage; Scene scene; @Override public void start(Stage primaryStage) throws Exception { this.stage = primaryStage; // 创建后台任务处理耗时加载 Task<Void> loadTask = new Task<>() { @Override protected Void call() throws Exception { // 模拟后端加载过程,运行在后台线程,不会阻塞UI Thread.sleep(5000); return null; } }; // 任务完成后,在UI线程加载主界面并通知预加载器关闭启动画面 loadTask.setOnSucceeded(event -> { try { FXMLLoader mainLoader = new FXMLLoader(getClass().getClassLoader().getResource("layouts/main.fxml")); AnchorPane pane = mainLoader.load(); scene = new Scene(pane, 600, 445); primaryStage.setScene(scene); primaryStage.show(); notifyPreloader(new StateChangeNotification(StateChangeNotification.Type.BEFORE_START)); } catch (Exception e) { e.printStackTrace(); } }); // 启动后台任务 new Thread(loadTask).start(); } }
2. (可选)启动画面播放视频的实现
如果要在启动画面播放视频,只需修改SplashScreen类和对应的fxml文件:
修改后的splash.fxml
<StackPane xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1"> <children> <MediaView fx:id="mediaView" fitHeight="374.0" fitWidth="686.0" pickOnBounds="true" preserveRatio="true"/> </children> </StackPane>
修改后的SplashScreen类
package com.example; import javafx.application.Preloader; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.layout.StackPane; import javafx.scene.media.Media; import javafx.scene.media.MediaPlayer; import javafx.scene.media.MediaView; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.stage.StageStyle; public class SplashScreen extends Preloader { Stage stage; private MediaPlayer mediaPlayer; @Override public void start(Stage stage) throws Exception { this.stage = stage; FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("layouts/splash.fxml")); StackPane root = loader.load(); // 初始化视频播放器 Media media = new Media(getClass().getResource("/test.mp4").toExternalForm()); mediaPlayer = new MediaPlayer(media); MediaView mediaView = loader.getNamespace().get("mediaView"); mediaView.setMediaPlayer(mediaPlayer); // 设置循环播放 mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE); mediaPlayer.play(); Scene scene = new Scene(root, 690, 380, true, SceneAntialiasing.BALANCED); scene.setFill(Color.TRANSPARENT); stage.initStyle(StageStyle.UNDECORATED); stage.setScene(scene); stage.show(); } @Override public void handleApplicationNotification(PreloaderNotification pn) { if (pn instanceof StateChangeNotification) { // 停止视频播放并关闭启动窗口 mediaPlayer.stop(); stage.hide(); } } }
核心原理总结
不管是GIF还是视频,它们的渲染/播放都依赖JavaFX应用线程的正常运行。只要把所有耗时操作移到后台线程,让UI线程保持空闲,启动画面的动态内容就能正常播放了。
内容的提问来源于stack exchange,提问作者Jawad El Fou
相关产品推荐
相关产品推荐

