Как я могу остановить анимированный GIF в JavaFX?

Я хочу использовать анимированный GIF в своем проекте, но я не знаю, как остановить циклическую анимацию. Я имею в виду, я хочу, чтобы GIF воспроизводился только 1 раз.

Спасибо!


person Ezequiel    schedule 28.01.2015    source источник


Ответы (1)


Я не занимался анимацией GIF, даже не знал, что у JavaFX есть методы для их запуска и остановки. Если вы хотите сделать ЛЮБУЮ анимацию с использованием изображений, я предлагаю вам сделать это кадр за кадром самостоятельно. Таким образом, у вас есть полный контроль над ним, и вы можете иметь более 256 цветов в своем изображении.

Я прочитал очень хорошую статью о Создание анимации спрайтов с помощью JavaFX в блоге Майка.

Это очень легко сделать. Вы просто расширяете класс Transition, добавляете ImageView к нему и реализовать переход метод интерполяции.

Редактировать: о, и, кстати, у GIF есть флаг цикла, который говорит им либо воспроизводиться в цикле, либо не воспроизводиться в цикле. Другими словами: теоретически вы можете изменить свойство цикла файла GIF. Только теоретически, потому что я только что попытался указать, чтобы играть только один раз, и в JavaFX он все еще проигрывался в бесконечном цикле, а в FireFox - один раз. Кстати, JavaFX, похоже, не поддерживает анимированные PNG (APNG), которые поддерживают более 256 цветов. Таким образом, возможности автоматической анимации изображений очень ограничены. Лучше всего сделать анимацию самостоятельно.

Я надеюсь, что кто-то придумает что-нибудь получше, но вот пример кода о том, как вы можете получить полный контроль над своим gif.

import java.awt.image.BufferedImage;
import java.net.URISyntaxException;

import javafx.animation.Interpolator;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 * Requires GifDecoder from here: http://www.java2s.com/Code/Java/2D-Graphics-GUI/DecodesaGIFfileintooneormoreframes.htm
 */
public class AnimatedGifDemo extends Application {

    @Override
    public void start(Stage primaryStage) throws URISyntaxException {

        HBox root = new HBox();

        // TODO: provide gif file, ie exchange banana.gif with your file
        Animation ani = new AnimatedGif(getClass().getResource("banana.gif").toExternalForm(), 1000);
        ani.setCycleCount(10);
        ani.play();

        Button btPause = new Button( "Pause");
        btPause.setOnAction( e -> ani.pause());

        Button btResume = new Button( "Resume");
        btResume.setOnAction( e -> ani.play());

        root.getChildren().addAll( ani.getView(), btPause, btResume);

        Scene scene = new Scene(root, 1600, 900);

        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }

    public class AnimatedGif extends Animation {

        public AnimatedGif( String filename, double durationMs) {

            GifDecoder d = new GifDecoder();
            d.read( filename);

            Image[] sequence = new Image[ d.getFrameCount()];
            for( int i=0; i < d.getFrameCount(); i++) {

                WritableImage wimg = null;
                BufferedImage bimg = d.getFrame(i);
                sequence[i] = SwingFXUtils.toFXImage( bimg, wimg);

            }

            super.init( sequence, durationMs);
        }

    }

    public class Animation extends Transition {

        private ImageView imageView;
        private int count;

        private int lastIndex;

        private Image[] sequence;

        private Animation() {
        }

        public Animation( Image[] sequence, double durationMs) {
            init( sequence, durationMs);
        }

        private void init( Image[] sequence, double durationMs) {
            this.imageView = new ImageView(sequence[0]);
            this.sequence = sequence;
            this.count = sequence.length;

            setCycleCount(1);
            setCycleDuration(Duration.millis(durationMs));
            setInterpolator(Interpolator.LINEAR);

        }

        protected void interpolate(double k) {

            final int index = Math.min((int) Math.floor(k * count), count - 1);
            if (index != lastIndex) {
                imageView.setImage(sequence[index]);
                lastIndex = index;
            }

        }

        public ImageView getView() {
            return imageView;
        }

    }

}

Он предоставляет кнопку паузы/возобновления для тестирования. Кроме того, вам понадобится код декодера Gif и анимированный banana.gif.

введите здесь описание изображения

person Roland    schedule 28.01.2015
comment
Большое спасибо, Роланд, очень полезная информация! - person Ezequiel; 28.01.2015
comment
Пожалуйста. Я обновил код, добавив специальный класс AnimatedGif и встроенный в JavaFX механизм преобразования BufferedImage -> Image. - person Roland; 28.01.2015
comment
Я знаю, что это старый пост, но откуда в нем btPause.setOnAction( e -> ani.pause()); e? Вроде загадочная буква, но работает, а переменную e найти не могу. - person ; 24.12.2017
comment
@sand_storm_of_code.txt — это лямбда-версия обработчика действий кнопки. e представляет event в ActionEvent event. По сути, это короткая версия примера 3 setOnAction здесь. - person Sedrick; 14.01.2018