我正在为 .NET Maui 开发一个需要扫描渐变的绘制自定义控件。 Maui 提供线性和径向渐变,但不提供扫描渐变。我知道 SkiaSharp 和 Android 提供扫描渐变,但我不想依赖第三方库,并且我需要一个跨平台的实现。如果我有渲染扫描渐变的基本逻辑,我可以自己实现它,但我无法在任何地方找到这样的逻辑。有人可以为我提供解决方案吗?
我在网上搜索过,没有发现任何适用的内容。我查看了 Skia 代码,但发现它几乎无法破译。我本来希望找到一种可以使用的算法,但到目前为止还没有成功。
这并不是真正的解决方案(.net maui 的实际库将于今年晚些时候发布),但您可以在自定义控件中使用一些代码。下面的Xaml只是为了演示一个用例,这是扫一个自动速度表的尾部(0.933->1.0,#CB6235->#00CB6235),而整个仪表被涂成纯色(0->0.933, #CB6235):
<draw:SkiaShape.StrokeGradient>
<draw:SkiaGradient Type="Sweep">
<draw:SkiaGradient.Colors>
<Color>#CB6235</Color>
<Color>#CB6235</Color>
<Color>#00CB6235</Color>
</draw:SkiaGradient.Colors>
<draw:SkiaGradient.ColorPositions>
<x:Double>0.0</x:Double>
<x:Double>0.933</x:Double>
<x:Double>1.0</x:Double>
</draw:SkiaGradient.ColorPositions>
</draw:SkiaGradient>
</draw:SkiaShape.StrokeGradient>
绘图背后的代码正在创建一个着色器,您可以将其添加到 SKPaint 中并用它绘制形状。平铺默认为
SKShaderTileMode.Clamp
。
public SKShader CreateGradientAsShader(SKRect destination, SkiaGradient gradient)
{
if (gradient != null && gradient.Type != GradientType.None)
{
var colors = new List<SKColor>();
foreach (var color in gradient.Colors.ToList())
{
var usingColor = color;
if (gradient.Light < 1.0)
{
usingColor = usingColor.MakeDarker(100 - gradient.Light * 100);
}
else if (gradient.Light > 1.0)
{
usingColor = usingColor.MakeLighter(gradient.Light * 100 - 100);
}
var newAlpha = usingColor.Alpha * gradient.Opacity;
usingColor = usingColor.WithAlpha(newAlpha);
colors.Add(usingColor.ToSKColor());
}
float[] colorPositions = null;
if (gradient.ColorPositions?.Count == colors.Count)
{
colorPositions = gradient.ColorPositions.Select(x => (float)x).ToArray();
}
switch (gradient.Type)
{
case GradientType.Sweep:
return SKShader.CreateSweepGradient(
new SKPoint(destination.Left + destination.Width / 2.0f,
destination.Top + destination.Height / 2.0f),
colors.ToArray(),
colorPositions,
gradient.TileMode, (float)Value1, (float)(Value1 + Value2));
case GradientType.Circular:
return SKShader.CreateRadialGradient(
new SKPoint(destination.Left + destination.Width / 2.0f,
destination.Top + destination.Height / 2.0f),
Math.Max(destination.Width, destination.Height) / 2.0f,
colors.ToArray(),
colorPositions,
gradient.TileMode);
case GradientType.Linear:
default:
return SKShader.CreateLinearGradient(
new SKPoint(destination.Left + destination.Width * gradient.StartXRatio,
destination.Top + destination.Height * gradient.StartYRatio),
new SKPoint(destination.Left + destination.Width * gradient.EndXRatio,
destination.Top + destination.Height * gradient.EndYRatio),
colors.ToArray(),
colorPositions,
gradient.TileMode);
break;
}
}
return null;
}