在JavaFX中是否可以制作线性渐变的百分比?

3
考虑以下线性渐变'A'。通常,如果您将该刷子指定为矩形的背景,则无论大小如何,它都会将整个区域填充整个渐变色(见'B')。
我们想说“对于这个特定的控件,只使用刷子的前xx%进行填充”,这样我们就可以实现基于百分比的渐变填充,就像'C'中一样。 gradient示例图像

3
我认为你不能仅使用LinearGradient(编程或CSS)来完成这个任务。你可以尝试使用剪辑(查看Node.clip属性)。如果将具有渐变的节点保持原始大小,然后将其剪切到一半的宽度,那么我认为你只会看到50%的渐变效果。但也许有更好的方法。这可能也是一个_XY问题_。如果你解释一下你试图做什么,也许就可以提出替代方案了。 - Slaw
2
将进度条样式化以满足您的需求。如果您按照Slaw的建议编辑问题,可能会提供更有针对性的答案。 - jewelsea
2
请提供您尝试解决问题的源代码(Java和CSS)。 - jewelsea
2
不确定您所说的“50%”宽度是指什么。50%是相对于什么而言的?宽度是否在变化?图片D提供了一种解决方案:使用“全宽度”矩形并进行裁剪。 - James_D
1个回答

6
有很多方法可以解决这个问题。我提出了三个示例解决方案:
  1. 使用固定宽度的渐变。<- 这是我推荐的。
  2. 使用剪辑。
  3. 使用插值器。
所有提供的解决方案都采用简单的常量大小方法。如果您想要动态大小,可以通过在基础矩形宽度和高度上实现适当的监听器或绑定来更新相关的裁剪或渐变设置。 使用固定宽度的渐变 渐变是在固定坐标中定义而不是比例坐标(停止仍是比例的)。矩形本身具有总宽度的百分比宽度,并为整个宽度定义线性渐变。任何未适合矩形的渐变部分都不会显示,从而得到所需的结果。
LinearGradient gradient = new LinearGradient(
        0, 0, W, 0,
        false,
        CycleMethod.NO_CYCLE,
        new Stop(0, Color.LAWNGREEN),
        new Stop(.5, Color.YELLOW),
        new Stop(1, Color.ORANGERED)
);

return new Rectangle(W * visiblePortion, H, gradient);

使用剪辑

这里,我们将剪辑应用于一个具有渐变的矩形,因此仅部分矩形可见。

Rectangle rect = new Rectangle(W, H);
rect.setStyle("-fx-fill: linear-gradient(to right, lawngreen, yellow, orangered);");

Rectangle clip = new Rectangle(W * visiblePortion, H);
rect.setClip(clip);

该示例使用css定义渐变,但如果您愿意,也可以使用LinearGradient API在Java代码中定义它。
使用插值器
如果您想要进行比例渐变而不需要所需样式中的剪辑,则需要调整渐变中使用的颜色和停止位置以匹配所需的百分比显示(使用您为计算创建的算法)。
对于两种颜色的平滑渐变,这很简单,但是对于具有多个停止位置的渐变定义,一般解决方案会更加复杂。我只在此处提供了两种颜色平滑渐变的解决方案。
实现使用Color.interpolate()函数(因为Color实现了Interpolatable)来计算渐变的停止颜色。
图像与基于剪辑的解决方案不同,因为基于剪辑的解决方案使用了更复杂的三段渐变,而此解决方案仅使用简单的两种颜色渐变。
该实现的关键在于使用插值器定义渐变:
LinearGradient gradient = new LinearGradient(
        0, 0, 1, 0,
        true,
        CycleMethod.NO_CYCLE,
        new Stop(0, Color.GREEN),
        new Stop(1, Color.GREEN.interpolate(Color.RED, visiblePortion))
);
return new Rectangle(W * visiblePortion, H, gradient);

使用进度条

这些图片看起来很像进度条。如果合适的话,您可以研究如何样式化进度条。我不会在这里提供渐变样式进度条的解决方案。如果您需要这个,请提一个新问题。

示例应用程序

screenshot

import javafx.application.Application;
import javafx.geometry.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.paint.*;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

import java.util.function.Function;

public class GradientDemo extends Application {
    private static final double W = 500;
    private static final double H = 10;
    private static final double STEP = 0.2;

    @Override
    public void start(Stage stage) {
        final VBox layout = new VBox(10);
        layout.setAlignment(Pos.TOP_LEFT);
        layout.setPadding(new Insets(10));

        addGradients(layout, "fixedWidthTriColorGradient", this::fixedWidthTriColorGradient);
        addGradients(layout, "clippedTriColorGradient", this::clippedTriColorGradient);
        addGradients(layout, "interpolatedTwoColorGradient", this::interpolatedTwoColorGradient);

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private void addGradients(
            VBox layout,
            String gradientName,
            Function<Double, Node> gradientFactory
    ) {
        Label label = new Label(gradientName);
        label.setPadding(new Insets(5, 0, 0, 0));
        layout.getChildren().addAll(
                label
        );
        for (double f = STEP; f <= 1.0; f += STEP) {
            layout.getChildren().addAll(gradientFactory.apply(f));
        }
    }

    public Rectangle fixedWidthTriColorGradient(double visiblePortion) {
        LinearGradient gradient = new LinearGradient(
                0, 0, W, 0,
                false,
                CycleMethod.NO_CYCLE,
                new Stop(0, Color.LAWNGREEN),
                new Stop(.5, Color.YELLOW),
                new Stop(1, Color.ORANGERED)
        );

        return new Rectangle(W * visiblePortion, H, gradient);
    }

    public Rectangle clippedTriColorGradient(double visiblePortion) {
        Rectangle rect = new Rectangle(W, H);
        rect.setStyle("-fx-fill: linear-gradient(to right, lawngreen, yellow, orangered);");

        Rectangle clip = new Rectangle(W * visiblePortion, H);
        rect.setClip(clip);

        return rect;
    }

    public Rectangle interpolatedTwoColorGradient(double visiblePortion) {
        LinearGradient gradient = new LinearGradient(
                0, 0, 1, 0,
                true,
                CycleMethod.NO_CYCLE,
                new Stop(0, Color.GREEN),
                new Stop(1, Color.GREEN.interpolate(Color.RED, visiblePortion))
        );

        return new Rectangle(W * visiblePortion, H, gradient);
    }

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接