Как анимировать градиент фона JavaFX светлыми цветами - PullRequest
0 голосов
/ 01 июня 2018

Я ищу решение для анимации градиента светлого цвета фона.Я просмотрел другие примеры с KeyFrames и не смог сделать это сам.

Поэтому я сделал примитивную версию того, что мне нужно:

boolean rbottomforward = true;
boolean gbottomforward = true;
boolean bbottomforward = true;
int redbottom = 171;
int greenbottom = 186;
int bluebottom = 171;

boolean rtopforward = true;
boolean gtopforward = true;
boolean btopforward = true;
int redtop = 255;
int greentop = 255;
int bluetop = 255;

@Override
protected Void call() throws Exception {
    Timeline backgroundAnimator = new Timeline(new KeyFrame(Duration.millis(200), event -> {
        backgroundPane.getStylesheets().clear();
        backgroundPane.setStyle("-fx-background-color: linear-gradient(to top, "+ randomBottomColor()+", "+randomTopColor()+");");

    }));
    backgroundAnimator.setCycleCount(Timeline.INDEFINITE);
    backgroundAnimator.play();
    return null;
}

private String randomBottomColor() {
    greenbottom = newBottomGreen();
    redbottom = newBottomRed();
    bluebottom = newBottomBlue();
    return String.format("rgb(%d,%d,%d)", redbottom, greenbottom, bluebottom);
}

private int newBottomGreen() {
    if(greenbottom <255 && greenbottom >155){
        if(gbottomforward)
greenbottom +=getRandomNumber();
        else
greenbottom -=getRandomNumber();
    } else if(greenbottom >=255) {
        gbottomforward=false;
        greenbottom -=getRandomNumber();
    } else {
        gbottomforward=true;
        greenbottom +=getRandomNumber();
    }
    return greenbottom;
}

private int getRandomNumber() {
    int r = (int) (Math.random() * (3 - 1)) + 1;
    return r;
}

private int newBottomRed() {
    if(redbottom <255 && redbottom >155){
        if(rbottomforward)
redbottom +=getRandomNumber();
        else
redbottom -=getRandomNumber();
    } else if(redbottom >=255) {
        rbottomforward=false;
        redbottom -=getRandomNumber();
    } else {
        rbottomforward=true;
        redbottom +=getRandomNumber();
    }
    return redbottom;
}

private int newBottomBlue() {
    if(bluebottom <255 && bluebottom >155){
        if(bbottomforward)
bluebottom +=getRandomNumber();
        else
bluebottom -=getRandomNumber();
    } else if(bluebottom >=255) {
        bbottomforward=false;
        bluebottom -=getRandomNumber();
    } else{
        bbottomforward=true;
        bluebottom +=getRandomNumber();
    }
    return bluebottom;
}
private String randomTopColor() {
    greentop = newTopGreen();
    redtop = newTopRed();
    bluetop = newTopBlue();
    return String.format("rgb(%d,%d,%d)", redtop, greentop, bluetop);
}

private int newTopGreen() {
    if(greentop <255 && greentop >155){
        if(gtopforward)
greentop +=getRandomNumber();
        else
greentop -=getRandomNumber();
    } else if(greentop >=255) {
        gtopforward=false;
        greentop -=getRandomNumber();
    } else {
        gtopforward=true;
        greentop +=getRandomNumber();
    }
    return greentop;
}

private int newTopRed() {
    if(redtop <255 && redtop >155){
        if(rtopforward)
redtop +=getRandomNumber();
        else
redtop -=getRandomNumber();
    } else if(redtop >=255) {
        rtopforward=false;
        redtop -=getRandomNumber();
    } else {
        rtopforward=true;
        redtop +=getRandomNumber();
    }
    return redtop;
}

private int newTopBlue() {
    if(bluetop <255 && bluetop >155){
        if(btopforward)
bluetop +=getRandomNumber();
        else
bluetop -=getRandomNumber();
    } else if(bluetop >=255) {
        btopforward=false;
        bluetop -=getRandomNumber();
    } else{
        btopforward=true;
        bluetop +=getRandomNumber();
    }
    return bluetop;
}

Это немного излишне.Может ли кто-нибудь помочь мне преобразовать это в более продвинутый уровень кода.Спасибо:)

1 Ответ

0 голосов
/ 01 июня 2018

На самом деле вы ничего не можете с этим поделать, но уменьшите количество повторений в коде.(Вы не сможете ничего интерполировать, поскольку при каждом обновлении следующий цвет выбирается случайным образом.)

Вы должны использовать один и тот же код для всех цветовых каналов:

/**
 * Class containing logic for a single color channel.
 */
private class AnimatedChannel {
    private boolean increment = true;
    private int value;

    AnimatedChannel(int value) {
        this.value = value;
    }

    /**
     * Changes channel by random amount in [1, 3] keeping it in range [155, 255] 
     */
    private void update() {
        int delta = getRandomNumber();
        if (increment) {
            value += delta;
            if (value > 0xFF) {
                value = (2 * 0xFF) - value; // v = max - (v - max)
                increment = false;
            }
        } else {
            value -= delta;
            if (value < 155) {
                value = (2 * 155) - value; // v = min + (min - v)
                increment = true;
            }
        }
    }
}

private final Random random = new Random();

private int getRandomNumber() {
    return random.nextInt(3 - 1) + 1;
}

private final AnimatedChannel bottomRed = new AnimatedChannel(171);
private final AnimatedChannel bottomGreen = new AnimatedChannel(186);
private final AnimatedChannel bottomBlue = new AnimatedChannel(171);

private final AnimatedChannel topRed = new AnimatedChannel(0xFF);
private final AnimatedChannel topGreen = new AnimatedChannel(0xFF);
private final AnimatedChannel topBlue = new AnimatedChannel(0xFF);

private final AnimatedChannel[] channels = new AnimatedChannel[] {
    bottomRed,
    bottomGreen,
    bottomBlue,
    topRed,
    topGreen,
    topBlue
};

@Override
protected Void call() throws Exception {
    Timeline backgroundAnimator = new Timeline(new KeyFrame(Duration.millis(200), event -> {
        for (AnimatedChannel channel : channels) {
            channel.update();
        }
        backgroundPane.setBackground(new Background(new BackgroundFill(
            new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE,
                new Stop(0, channelsToColor(topRed, topGreen, topBlue)),
                new Stop(1, channelsToColor(bottomRed, bottomGreen, bottomBlue))),
            CornerRadii.EMPTY,
            Insets.EMPTY)));
    }));
    backgroundAnimator.setCycleCount(Timeline.INDEFINITE);
    backgroundAnimator.play();
    return null;
}

private static Color channelsToColor(AnimatedChannel red, AnimatedChannel green, AnimatedChannel blue) {
    return Color.rgb(red.value, green.value, blue.value);
}

Этот код не намного короче вашего кода, но его легче поддерживать.Если вы хотите изменить логику обновления каналов, вам нужно настроить только 1 метод вместо 6 методов.Кроме того, это освобождает JavaFX от необходимости разбора встроенного CSS при каждом обновлении.

Примечание:

Похоже, вы расширяете Task<Void> или что-то подобное, связанное с параллелизмомучебный класс.В этом нет необходимости, поскольку Timeline.play не является длительной операцией, а просто запускает повторное выполнение логики (в данном случае EventHandler<ActionEvent>) в потоке приложения в более позднее время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...