你的主要
SequentialTransition
正在加载所有图像并在开始播放之前保留对它们的引用。因此,这种技术不会随着图像数量的增加而扩展(这意味着,如果您有足够的图像,那么一定会耗尽堆空间)。
如果您的图像从
BufferedImage
s到FX
Image
很快,您可以使用时间线来完成这项工作:
private void createSlideshow(Stage stage, ArrayList<BufferedImage> slideList, int durationInSecs) throws InterruptedException {
stage.show();
Timeline slideshow = new Timeline();
ImageView slide = new ImageView();
for (int i = 0; i < slideList.size(); i++) {
BufferedImage bi = slideList.get(i);
KeyFrame newImageFrame = new KeyFrame(Duration.seconds(durationInSeconds * 3 * i), e ->
slide.setImage(SwingFXUtils.toFXImage(bi, null)));
KeyFrame startFadeIn = new KeyFrame(Duration.seconds(durationInSeconds * 3 * i),
new KeyValue(slide.opacityProperty(), 0));
KeyFrame endFadeIn = new KeyFrame(Duration.seconds(durationsInSeconds * (3 * i + 1)),
new KeyValue(slide.opacityProperty(), 1));
KeyFrame startFadeOut = new KeyFrame(Duration.seconds(durationInSeconds * (3 * i + 2)),
new KeyValue(slide.opacityProperty(), 1));
slideshow.getKeyFrames().addAll(newImageFrame, startFadeIn, endFadeIn, startFadeOut);
}
slideshow.play();
}
在这个实现中,您创建了一个时间线,每个图像有四个关键帧。第一个转换电流
缓冲图像
到JavaFX
形象
,而注册的下一个(在同一时间点)将不透明度设置为零。下一个关键帧的不透明度设置为1(因此时间轴将在这两个关键帧之间插入不透明度)。最后一个关键帧的不透明度也为1,因此它将在时间线的该部分保持不变。在循环的下一次迭代中,将添加一个不透明度为0的新关键帧,因此,一次迭代的最后一个关键帧和循环的下个迭代的关键帧之间的插值将创建淡出。
如果图像需要一些时间来转换,那么这个实现可能会由于图像出现之前的延迟而出现一些抖动,从而破坏“淡入”效果。解决此问题的一种方法是使用后台线程来转换图像并将其放入绑定的阻塞队列:
private void createSlideshow(Stage stage, ArrayList<BufferedImage> slideList, int durationInSecs) throws InterruptedException {
stage.show();
int numImages = slideList.size();
BlockingQueue<Image> images = new ArrayBlockingQueue<>(3);
Thread conversionThread = new Thread(() -> {
for (BufferedImage bi : slideList) {
try {
images.put(SwingFXUtils.toFXImage(bi, null));
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
}
}
});
conversionThread.setDaemon(true);
conversionThread.start();
Timeline slideshow = new Timeline();
ImageView slide = new ImageView();
for (int i = 0; i < slideList.size(); i++) {
KeyFrame newImageFrame = new KeyFrame(Duration.seconds(durationInSeconds * 3 * i), e ->
slide.setImage(images.poll()));
KeyFrame startFadeIn = new KeyFrame(Duration.seconds(durationInSeconds * 3 * i),
new KeyValue(slide.opacityProperty(), 0));
KeyFrame endFadeIn = new KeyFrame(Duration.seconds(durationsInSeconds * (3 * i + 1)),
new KeyValue(slide.opacityProperty(), 1));
KeyFrame startFadeOut = new KeyFrame(Duration.seconds(durationInSeconds * (3 * i + 2)),
new KeyValue(slide.opacityProperty(), 1));
slideshow.getKeyFrames().addAll(newImageFrame, startFadeIn, endFadeIn, startFadeOut);
}
slideshow.play();
}
最后请注意,您的原始代码以及这两个实现都需要一个列表
缓冲图像
s传递给方法。这已经消耗了大量内存:在进入方法体之前,您基本上已经在内存中保存了所有图像。根据这些图像的来源,例如,您可以传递
File
对象,并在这里使用相同的技术根据需要动态加载每个图像(或像第二个示例中那样创建一个小队列)。这将基本上缩放到任意数量的图像。