Browse Source

Support gradients with not matched number of stops

pull/6183/head
Max Katz 5 years ago
parent
commit
b05ff7ccd8
  1. 65
      samples/RenderDemo/Pages/AnimationsPage.xaml
  2. 38
      src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs

65
samples/RenderDemo/Pages/AnimationsPage.xaml

@ -172,7 +172,7 @@
</KeyFrame> </KeyFrame>
<KeyFrame Cue="30%"> <KeyFrame Cue="30%">
<Setter Property="Background"> <Setter Property="Background">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Red"/> <GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/> <GradientStop Offset="1" Color="Blue"/>
</LinearGradientBrush> </LinearGradientBrush>
@ -183,7 +183,7 @@
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="100%">
<Setter Property="Background"> <Setter Property="Background">
<LinearGradientBrush StartPoint="100%,0%" EndPoint="0%,100%"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Green"/> <GradientStop Offset="0" Color="Green"/>
<GradientStop Offset="1" Color="Yellow"/> <GradientStop Offset="1" Color="Yellow"/>
</LinearGradientBrush> </LinearGradientBrush>
@ -200,20 +200,31 @@
PlaybackDirection="Alternate"> PlaybackDirection="Alternate">
<KeyFrame Cue="0%"> <KeyFrame Cue="0%">
<Setter Property="Background"> <Setter Property="Background">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Red"/> <GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/> <GradientStop Offset="1" Color="Blue"/>
</LinearGradientBrush> </LinearGradientBrush>
</Setter> </Setter>
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="50%">
<Setter Property="Background"> <Setter Property="Background">
<LinearGradientBrush StartPoint="100%,0%" EndPoint="0%,100%"> <LinearGradientBrush StartPoint="100%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Green"/> <GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="0.25" Color="Blue"/>
<GradientStop Offset="0.5" Color="Blue"/>
<GradientStop Offset="0.75" Color="Green"/>
<GradientStop Offset="1" Color="Yellow"/> <GradientStop Offset="1" Color="Yellow"/>
</LinearGradientBrush> </LinearGradientBrush>
</Setter> </Setter>
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Background">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/>
</LinearGradientBrush>
</Setter>
</KeyFrame>
</Animation> </Animation>
</Style.Animations> </Style.Animations>
</Style> </Style>
@ -226,16 +237,20 @@
<KeyFrame Cue="0%"> <KeyFrame Cue="0%">
<Setter Property="Background"> <Setter Property="Background">
<ConicGradientBrush Center="50%,50%" Angle="0"> <ConicGradientBrush Center="50%,50%" Angle="0">
<GradientStop Offset="0" Color="Red"/> <GradientStop Offset="0" Color="Blue"/>
<GradientStop Offset="0.5" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/> <GradientStop Offset="1" Color="Blue"/>
</ConicGradientBrush> </ConicGradientBrush>
</Setter> </Setter>
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="100%">
<Setter Property="Background"> <Setter Property="Background">
<ConicGradientBrush Center="70%,70%" Angle="90"> <ConicGradientBrush Center="50%,70%" Angle="90">
<GradientStop Offset="0" Color="Green"/> <GradientStop Offset="0" Color="Green"/>
<GradientStop Offset="1" Color="Yellow"/> <GradientStop Offset="0.25" Color="Yellow"/>
<GradientStop Offset="0.5" Color="Red"/>
<GradientStop Offset="0.75" Color="Blue"/>
<GradientStop Offset="1" Color="Green"/>
</ConicGradientBrush> </ConicGradientBrush>
</Setter> </Setter>
</KeyFrame> </KeyFrame>
@ -247,10 +262,34 @@
<Style.Animations> <Style.Animations>
<Animation Duration="0:0:3" <Animation Duration="0:0:3"
IterationCount="Infinite" IterationCount="Infinite"
PlaybackDirection="Alternate"> PlaybackDirection="Normal">
<KeyFrame Cue="0%"> <KeyFrame Cue="0%">
<Setter Property="Background"> <Setter Property="Background">
<RadialGradientBrush Center="50%,50%" Radius="0.5"> <RadialGradientBrush Center="0%,100%" Radius="0.8">
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/>
</RadialGradientBrush>
</Setter>
</KeyFrame>
<KeyFrame Cue="25%">
<Setter Property="Background">
<RadialGradientBrush Center="0%,0%" Radius="1">
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/>
</RadialGradientBrush>
</Setter>
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="Background">
<RadialGradientBrush Center="100%,0%" Radius="0.8">
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/>
</RadialGradientBrush>
</Setter>
</KeyFrame>
<KeyFrame Cue="75%">
<Setter Property="Background">
<RadialGradientBrush Center="100%,100%" Radius="1">
<GradientStop Offset="0" Color="Red"/> <GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/> <GradientStop Offset="1" Color="Blue"/>
</RadialGradientBrush> </RadialGradientBrush>
@ -258,9 +297,9 @@
</KeyFrame> </KeyFrame>
<KeyFrame Cue="100%"> <KeyFrame Cue="100%">
<Setter Property="Background"> <Setter Property="Background">
<RadialGradientBrush Center="30%,30%" Radius="0.2"> <RadialGradientBrush Center="0%,100%" Radius="0.8">
<GradientStop Offset="0" Color="Green"/> <GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Yellow"/> <GradientStop Offset="1" Color="Blue"/>
</RadialGradientBrush> </RadialGradientBrush>
</Setter> </Setter>
</KeyFrame> </KeyFrame>

38
src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs

@ -19,8 +19,7 @@ namespace Avalonia.Animation.Animators
public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue) public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue)
{ {
if (oldValue is null || newValue is null if (oldValue is null || newValue is null)
|| oldValue.GradientStops.Count != newValue.GradientStops.Count)
{ {
return progress >= 0.5 ? newValue : oldValue; return progress >= 0.5 ? newValue : oldValue;
} }
@ -64,13 +63,26 @@ namespace Avalonia.Animation.Animators
private IReadOnlyList<ImmutableGradientStop> InterpolateStops(double progress, IReadOnlyList<IGradientStop> oldValue, IReadOnlyList<IGradientStop> newValue) private IReadOnlyList<ImmutableGradientStop> InterpolateStops(double progress, IReadOnlyList<IGradientStop> oldValue, IReadOnlyList<IGradientStop> newValue)
{ {
var stops = new ImmutableGradientStop[oldValue.Count]; var resultCount = Math.Max(oldValue.Count, newValue.Count);
for (int index = 0; index < oldValue.Count; index++) var stops = new ImmutableGradientStop[resultCount];
for (int index = 0, oldIndex = 0, newIndex = 0; index < resultCount; index++)
{ {
stops[index] = new ImmutableGradientStop( stops[index] = new ImmutableGradientStop(
s_doubleAnimator.Interpolate(progress, oldValue[index].Offset, newValue[index].Offset), s_doubleAnimator.Interpolate(progress, oldValue[oldIndex].Offset, newValue[newIndex].Offset),
ColorAnimator.InterpolateCore(progress, oldValue[index].Color, newValue[index].Color)); ColorAnimator.InterpolateCore(progress, oldValue[oldIndex].Color, newValue[newIndex].Color));
if (oldIndex < oldValue.Count - 1)
{
oldIndex++;
}
if (newIndex < newValue.Count - 1)
{
newIndex++;
}
} }
return stops; return stops;
} }
@ -80,29 +92,29 @@ namespace Avalonia.Animation.Animators
{ {
case IRadialGradientBrush oldRadial: case IRadialGradientBrush oldRadial:
return new ImmutableRadialGradientBrush( return new ImmutableRadialGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial), solidColorBrush.Opacity, CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity,
oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius);
case IConicGradientBrush oldConic: case IConicGradientBrush oldConic:
return new ImmutableConicGradientBrush( return new ImmutableConicGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldConic), solidColorBrush.Opacity, CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity,
oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); oldConic.SpreadMethod, oldConic.Center, oldConic.Angle);
case ILinearGradientBrush oldLinear: case ILinearGradientBrush oldLinear:
return new ImmutableLinearGradientBrush( return new ImmutableLinearGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear), solidColorBrush.Opacity, CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity,
oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint);
default: default:
throw new NotSupportedException($"Gradient of type {gradientBrush?.GetType()} is not supported"); throw new NotSupportedException($"Gradient of type {gradientBrush?.GetType()} is not supported");
} }
static IReadOnlyList<ImmutableGradientStop> CreateStopsFromSolidColorBrush(ISolidColorBrush solidColorBrush, IGradientBrush baseGradient) static IReadOnlyList<ImmutableGradientStop> CreateStopsFromSolidColorBrush(ISolidColorBrush solidColorBrush, IReadOnlyList<IGradientStop> baseStops)
{ {
var stops = new ImmutableGradientStop[baseGradient.GradientStops.Count]; var stops = new ImmutableGradientStop[baseStops.Count];
for (int index = 0; index < baseGradient.GradientStops.Count; index++) for (int index = 0; index < baseStops.Count; index++)
{ {
stops[index] = new ImmutableGradientStop(baseGradient.GradientStops[index].Offset, solidColorBrush.Color); stops[index] = new ImmutableGradientStop(baseStops[index].Offset, solidColorBrush.Color);
} }
return stops; return stops;
} }

Loading…
Cancel
Save