有没有办法影响WPF中半透明颜色之间的插值?

问题描述 投票:0回答:1

正如这个问题中所讨论的那样,我希望以下代码会产生两个相同的looking渐变:

<Border Background="Black">
    <StackPanel>
        <Border x:Name="withOpacity" Height="32">
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                    <GradientStop Offset="0" Color="#ff222222" />
                    <GradientStop Offset="1" Color="#33ff8000" />
                </LinearGradientBrush>
            </Border.Background>
        </Border>
        <Border x:Name="withoutOpacity" Height="32">
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                    <GradientStop Offset="0" Color="#ff222222" />
                    <GradientStop Offset="1" Color="#ff331a00" />
                </LinearGradientBrush>
            </Border.Background>
        </Border>
    </StackPanel>
</Border>

两个渐变的 visible 开始和结束颜色是相同的(在第二个渐变中,最终颜色是通过在给定的

#33
不透明度(即 20%)下将第一个渐变的结束颜色与黑色背景混合来计算的) )。不幸的是,插值非常不同:

上面链接的问题的公认答案解释了为什么会出现这种情况。我想知道是否有人能想到一种(编程)方法来在给定第一个梯度的输入值的情况下复制第二个梯度的插值。另外,我正在寻找渐变和彩色动画的解决方案。

我之前问题的回答者建议我可能只需要调整 alpha 分量的插值并且可以保留纯色值,但如果是这样的话,我还没有找到正确的算法......(由于最初的用例是动画,我在不透明度上尝试了各种缓动功能)经过一些实验,我也不再确定将不透明度与强度等同起来是否完全正确,就像该解释中的情况一样......

请注意,我并不是(必然)寻找现成的解决方案,而是寻找有关如何解决最可能有价值的问题的建议。例如。创建

ColorAnimation
*GradientBrush
的自定义实现 vs 添加更明确的
GradientStop
s/关键帧 vs ...我还没想到的东西?

我探索这一点的原因是,我非常喜欢使用半透明颜色而不是预混合颜色,因为它将使渐变和动画独立于它们显示的背景(理想情况下,还包括非固体)彩色背景)。

wpf colors interpolation
1个回答
0
投票

由于您知道渐变透明度的百分比,因此您可以计算黑色百分比并导出第二种颜色。您可以将此计算交给值转换器来为您完成工作。您可能需要调整此计算以获得您想要的结果,但它应该会让您走上正确的道路。

以下是值转换器的样子:

public class GradientNormalizer : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Color color)) return value;

        var opacity = color.ScA;
        var r = color.ScR;
        var g = color.ScG;
        var b = color.ScB;

        var normalizedColor = new Color
        {

            ScA = 1,
            // since color is interpreted as approximately square
            ScR = r * opacity * opacity,
            ScG = g * opacity * opacity,
            ScB = b * opacity * opacity,
        };


        return normalizedColor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这是您在 xaml 中使用它的方式

<Border x:Name="withOpacity"
        Height="32">
    <Border.Resources>
        <local:GradientNormalizer x:Key="Normalizer" />
    </Border.Resources>
    <Border.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
            <GradientStop Offset="0"
                          Color="{Binding StartColor, Converter={StaticResource Normalizer}}" />
            <GradientStop Offset="1"
                          Color="{Binding EndColor, Converter={StaticResource Normalizer}}" />
        </LinearGradientBrush>
    </Border.Background>
</Border>

本例中的数据模型:

public Color StartColor => (Color)ColorConverter.ConvertFromString("#ff222222");
public Color EndColor => (Color)ColorConverter.ConvertFromString("#33ff8000");

© www.soinside.com 2019 - 2024. All rights reserved.