JavaFX一对一显示多个GIF

时间:2019-03-25 16:37:45

标签: java javafx javafx-8 gif animated-gif

我要一个接一个地显示不同的gif。
我的想法是使用时间轴动态更改包装在图像中的显示gif。
但是我遇到了一个错误:

  从Lambda表达式引用的

局部变量必须是final或   有效地最终

有什么解决办法吗?
我的代码:

10000000

1 个答案:

答案 0 :(得分:1)

在Java中,在lambda或匿名类之外声明但在所述lambda或匿名类中使用的局部变量必须是“有效最终”变量。这就是说,本地变量永远不会被修改(即重新分配)。如果局部变量可以在声明中添加final关键字而不引起编译错误,则该变量实际上是最终变量。

在您的代码中,您具有以下内容:

public void show(ImageView currentGif, Image[] gifs) {
    for (int i = 0; i<gifs.length; i++) {
        Timeline timeline = new Timeline(
            new KeyFrame(Duration.ZERO, e -> { currentGif.setImage(gifs[i]); }),
            new KeyFrame(Duration.seconds(2), e -> { currentGif.setImage(null); })
        );
        timeline.play();
    }

}

您正在引用lambda(第一个i)内部的局部变量KeyFrame。问题是for循环修改了i(例如i++),这意味着该变量实际上不是最终变量。可能的解决方法是在循环内声明另一个变量,为其分配值i,然后在lambda内使用该新变量(不变!)。但是,这不是唯一的问题。

您的代码正在为Timeline数组中的每个元素创建单独的gifs-换句话说,每个循环一个。您还应在每次迭代结束时在每个play上调用Timeline。这将导致多个Timeline同时播放。如您所想,这不会做您想要的。相反,您应该创建一个单个 Timeline,并且使Image的每个更改都是它自己的KeyFrame。类似于以下内容:

public void show(ImageView view, Image[] gifs, Duration displayDuration) {
    Timeline timeline = new Timeline();

    Duration totalDelay = Duration.ZERO;
    for (Image gif : gifs) {
        KeyFrame frame = new KeyFrame(totalDelay, e -> view.setImage(gif));
        timeline.getFrames().add(frame);
        totalDelay = totalDelay.add(displayDuration);
    }
    timeline.getFrames().add(new KeyFrame(totalDelay, e -> view.setImage(null));

   timeline.play();
}

这将以Image的间隔将Image更改为数组中的下一个displayDuration

如果您想知道为什么允许gif在lambda中使用(尽管显然已被修改),这是因为我使用了“增强的循环”。与常规for循环相比,增强型for循环的变量与常规[]循环的区别在于每次迭代 initialized 。有关更多信息,请参见Enhanced 'for' loop and lambda expressions