正如这个问题中所讨论的那样,我希望以下代码会产生两个相同的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 ...我还没想到的东西?
我探索这一点的原因是,我非常喜欢使用半透明颜色而不是预混合颜色,因为它将使渐变和动画独立于它们显示的背景(理想情况下,还包括非固体)彩色背景)。
由于您知道渐变透明度的百分比,因此您可以计算黑色百分比并导出第二种颜色。您可以将此计算交给值转换器来为您完成工作。您可能需要调整此计算以获得您想要的结果,但它应该会让您走上正确的道路。
以下是值转换器的样子:
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");