Browse Source

Unify brush transition. Handle brush type mismatch in a nicer way.

Dariusz Komosinski 4 years ago
parent
commit
c48a516ec6

+ 22 - 1
samples/RenderDemo/Pages/TransitionsPage.xaml

@@ -145,7 +145,7 @@
       <Style Selector="Border.Rect10">
         <Setter Property="Transitions">
           <Transitions>
-            <ISolidColorBrushTransition Property="Background" Duration="0:0:0.5" />
+            <BrushTransition Property="Background" Duration="0:0:0.5" />
           </Transitions>
         </Setter>
         <Setter Property="Background" Value="Red" />
@@ -154,6 +154,26 @@
       <Style Selector="Border.Rect10:pointerover">
         <Setter Property="Background" Value="Orange" />
       </Style>
+
+      <Style Selector="Border.Rect11">
+        <Setter Property="Transitions">
+          <Transitions>
+            <BrushTransition Property="Background" Duration="0:0:0.5" />
+          </Transitions>
+        </Setter>
+        <Setter Property="Background" Value="Red" />
+      </Style>
+
+      <Style Selector="Border.Rect11:pointerover">
+        <Setter Property="Background" >
+          <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
+            <LinearGradientBrush.GradientStops>
+              <GradientStop Offset="0" Color="Red"/>
+              <GradientStop Offset="1" Color="Blue"/>
+            </LinearGradientBrush.GradientStops>
+          </LinearGradientBrush>
+        </Setter>
+      </Style>
     </Styles>
   </UserControl.Styles>
 
@@ -181,6 +201,7 @@
         <Border Classes="Test Shadow" CornerRadius="0 30 60 0" Child="{x:Null}" />
 
         <Border Classes="Test Rect10" />
+        <Border Classes="Test Rect11" />
       </WrapPanel>
     </StackPanel>
   </Grid>

+ 47 - 9
src/Avalonia.Visuals/Animation/Transitions/BrushTransition.cs

@@ -1,29 +1,67 @@
 using System;
 using Avalonia.Animation.Animators;
+using Avalonia.Animation.Easings;
 using Avalonia.Media;
 
+#nullable enable
+
 namespace Avalonia.Animation
 {
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="IBrush"/> type.
-    /// Only values of <see cref="ISolidColorBrush"/> will correctly transition.
+    /// Only values of <see cref="ISolidColorBrush"/> will transition correctly at the moment.
     /// </summary>
-    public class ISolidColorBrushTransition : Transition<IBrush>
+    public class BrushTransition : Transition<IBrush?>
     {
         private static readonly ISolidColorBrushAnimator s_animator = new ISolidColorBrushAnimator();
 
-        public override IObservable<IBrush> DoTransition(IObservable<double> progress, IBrush oldValue, IBrush newValue)
+        public override IObservable<IBrush?> DoTransition(IObservable<double> progress, IBrush? oldValue, IBrush? newValue)
+        {
+            var oldSolidColorBrush = TryGetSolidColorBrush(oldValue);
+            var newSolidColorBrush = TryGetSolidColorBrush(newValue);
+
+            if (oldSolidColorBrush != null && newSolidColorBrush != null)
+            {
+                EnsureImmutable(ref oldSolidColorBrush);
+                EnsureImmutable(ref newSolidColorBrush);
+
+                return new AnimatorTransitionObservable<ISolidColorBrush, ISolidColorBrushAnimator>(
+                    s_animator, progress, Easing, oldSolidColorBrush, newSolidColorBrush);
+            }
+
+            return new IncompatibleTransitionObservable(progress, Easing, oldValue, newValue);
+        }
+
+        private static void EnsureImmutable(ref ISolidColorBrush brush)
+        {
+            brush = (ISolidColorBrush)brush.ToImmutable();
+        }
+
+        private static ISolidColorBrush? TryGetSolidColorBrush(IBrush? brush)
         {
-            var oldSolidBrush = AsImmutable(oldValue);
-            var newSolidBrush = AsImmutable(newValue);
+            if (brush is null)
+            {
+                return Brushes.Transparent;
+            }
 
-            return new AnimatorTransitionObservable<ISolidColorBrush, ISolidColorBrushAnimator>(
-                s_animator, progress, Easing, oldSolidBrush, newSolidBrush);
+            return brush as ISolidColorBrush;
         }
 
-        private static ISolidColorBrush AsImmutable(IBrush brush)
+        private class IncompatibleTransitionObservable : TransitionObservableBase<IBrush?>
         {
-            return (ISolidColorBrush)(brush as ISolidColorBrush)?.ToImmutable();
+            private readonly IBrush? _from;
+            private readonly IBrush? _to;
+
+            public IncompatibleTransitionObservable(IObservable<double> progress, Easing easing, IBrush? from, IBrush? to) : base(progress, easing)
+            {
+                _from = @from;
+                _to = to;
+            }
+
+            protected override IBrush? ProduceValue(double progress)
+            {
+                return progress < 0.5 ? _from : _to;
+            }
         }
     }
 }