Explorar el Código

Implemented FillMode; This PR is now almost feature complete (that nasty Control.Class selector bug).

Jumar Macato hace 7 años
padre
commit
edf982b820

+ 27 - 7
samples/RenderTest/Pages/AnimationsPage.xaml

@@ -5,7 +5,23 @@
     <Styles>
       <Styles.Resources>
         <Template x:Key="Acorn">
-          <Path Fill="White" Stretch="Uniform" Data="F1 M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z"/>
+          <Path Fill="White" Stretch="Uniform" 
+          Data="F1 M 16.6309,18.6563C 17.1309,
+                8.15625 29.8809,14.1563 29.8809,
+                14.1563C 30.8809,11.1563 34.1308,
+                11.4063 34.1308,11.4063C 33.5,12 
+                34.6309,13.1563 34.6309,13.1563C 
+                32.1309,13.1562 31.1309,14.9062 
+                31.1309,14.9062C 41.1309,23.9062
+                32.6309,27.9063 32.6309,27.9062C 
+                24.6309,24.9063 21.1309,22.1562 
+                16.6309,18.6563 Z M 16.6309,19.9063C
+                21.6309,24.1563 25.1309,26.1562 
+                31.6309,28.6562C 31.6309,28.6562
+                26.3809,39.1562 18.3809,36.1563C
+                18.3809,36.1563 18,38 16.3809,36.9063C 
+                15,36 16.3809,34.9063 16.3809,34.9063C
+                16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z"/>
         </Template>
       </Styles.Resources>
       <Style Selector="Border.Test">
@@ -16,12 +32,16 @@
         <Setter Property="Child" Value="{StaticResource Acorn}"/>
       </Style>
       <Style Selector="Border.Rect1:pointerover">
-        <Setter Property="Opacity" Value="0.5"/>
         <Style.Animations>
-          <Animation Duration="0:0:2.5" Easing="SineEaseInOut" Delay="0:0:5">
+          <Animation Duration="0:0:2.5"
+                     RepeatBehavior="Repeat"
+                     RepeatCount="2"
+                     FillMode="Both"
+                     PlaybackDirection="AlternateReverse"
+                     Easing="SineEaseInOut">
             <TransformKeyFrames Property="RotateTransform.Angle">
-              <KeyFrame Cue="0%" Value="0"/>
-              <KeyFrame Cue="100%" Value="360"/>
+              <KeyFrame Cue="0%" Value="45"/>
+              <KeyFrame Cue="100%" Value="120"/>
             </TransformKeyFrames>
             <TransformKeyFrames Property="ScaleTransform.ScaleX">
               <KeyFrame Cue="0%" Value="1"/>
@@ -86,11 +106,11 @@
               <ScaleTransform/>
             </TransformGroup>
           </Border.RenderTransform>
-          <Border.Transitions>
+          <!-- <Border.Transitions>
             <Transitions>
               <DoubleTransition Property="Border.Opacity" Duration="0:0:2.5"/>
             </Transitions>
-          </Border.Transitions>
+          </Border.Transitions> -->
         </Border>
         <Border Classes="Test Rect2" Background="DarkMagenta">
           <Border.RenderTransform>

+ 11 - 24
src/Avalonia.Animation/Animatable.cs

@@ -27,7 +27,7 @@ namespace Avalonia.Animation
             AnimatableTimer = Timing.AnimationStateTimer
                                 .Select(p =>
                                 {
-                                    if (this._playState == PlayState.Pause)
+                                    if (PlayState == PlayState.Pause)
                                     {
                                         return PlayState.Pause;
                                     }
@@ -46,44 +46,31 @@ namespace Avalonia.Animation
         /// <summary>
         /// Defines the <see cref="PlayState"/> property.
         /// </summary>
-        public static readonly DirectProperty<Animatable, PlayState> PlayStateProperty =
-            AvaloniaProperty.RegisterDirect<Animatable, PlayState>(
-                nameof(PlayState),
-                o => o.PlayState,
-                (o, v) => o.PlayState = v);
-
-        private PlayState _playState = PlayState.Run;
+        public static readonly StyledProperty<PlayState> PlayStateProperty =
+            AvaloniaProperty.Register<Animatable, PlayState>(nameof(PlayState), PlayState.Run);
 
         /// <summary>
-        /// Gets or sets the state of the animation for this
-        /// control.
+        /// Gets or sets the property transitions for the control.
         /// </summary>
         public PlayState PlayState
         {
-            get { return _playState; }
-            set { SetAndRaise(PlayStateProperty, ref _playState, value); }
-
+            get { return GetValue(PlayStateProperty); }
+            set { SetValue(PlayStateProperty, value); }
         }
 
-
         /// <summary>
         /// Defines the <see cref="Transitions"/> property.
-        /// </summary>
-        public static readonly DirectProperty<Animatable, IEnumerable<ITransition>> TransitionsProperty =
-            AvaloniaProperty.RegisterDirect<Animatable, IEnumerable<ITransition>>(
-                nameof(Transitions),
-                o => o.Transitions,
-                (o, v) => o.Transitions = v);
-
-        private IEnumerable<ITransition> _transitions = new AvaloniaList<ITransition>();
+        /// </summary>  
+        public static readonly StyledProperty<IEnumerable<ITransition>> TransitionsProperty =
+            AvaloniaProperty.Register<Animatable, IEnumerable<ITransition>>(nameof(Transitions));
 
         /// <summary>
         /// Gets or sets the property transitions for the control.
         /// </summary>
         public IEnumerable<ITransition> Transitions
         {
-            get { return _transitions; }
-            set { SetAndRaise(TransitionsProperty, ref _transitions, value); }
+            get { return GetValue(TransitionsProperty); }
+            set { SetValue(TransitionsProperty, value); }
         }
 
         /// <summary>

+ 5 - 0
src/Avalonia.Animation/Animation.cs

@@ -37,6 +37,11 @@ namespace Avalonia.Animation
         /// </summary>
         public PlaybackDirection PlaybackDirection { get; set; }
 
+        /// <summary>
+        /// The value fill mode for this animation.
+        /// </summary>
+        public FillMode FillMode { get; set; }
+
         /// <summary>
         /// Number of repeat iteration for this animation.
         /// </summary>

+ 2 - 2
src/Avalonia.Animation/Keyframes/KeyFrames.cs

@@ -51,7 +51,7 @@ namespace Avalonia.Animation.Keyframes
         /// according to the given time parameter that is relative to
         /// total animation time and the normalized intra-keyframe pair time 
         /// (i.e., the normalized time between the selected keyframes, relative to the
-        /// give time parameter).
+        /// time parameter).
         /// </summary>
         /// <param name="t">The time parameter, relative to the total animation time</param>
         public (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double t)
@@ -95,7 +95,7 @@ namespace Avalonia.Animation.Keyframes
         public IDisposable RunKeyFrames(Animation animation, Animatable control)
         {
             var _kfStateMach = new KeyFramesStateMachine<T>();
-            _kfStateMach.Initialize(animation, control);
+            _kfStateMach.Initialize(animation, control, this);
 
             Timing.AnimationStateTimer
                         .TakeWhile(_ => !_kfStateMach._unsubscribe)

+ 43 - 10
src/Avalonia.Animation/Keyframes/KeyFramesStateMachine.cs

@@ -1,4 +1,6 @@
 using System;
+using System.Linq;
+using Avalonia.Data;
 
 namespace Avalonia.Animation.Keyframes
 {
@@ -7,9 +9,8 @@ namespace Avalonia.Animation.Keyframes
     /// </summary>
     internal class KeyFramesStateMachine<T> : IObservable<object>, IDisposable
     {
-        
         T _lastInterpValue = default(T);
-
+        T _firstKFValue = default(T);
         private ulong _delayTotalFrameCount,
             _durationTotalFrameCount,
             _delayFrameCount,
@@ -17,10 +18,16 @@ namespace Avalonia.Animation.Keyframes
             _repeatCount,
             _currentIteration;
 
-        private bool _isLooping, _isRepeating, _isReversed, _checkLoopAndRepeat;
+        private bool _isLooping,
+                     _isRepeating,
+                     _isReversed,
+                     _checkLoopAndRepeat,
+                     _gotFirstKFValue;
+        private FillMode _fillMode;
         private PlaybackDirection _animationDirection;
-        KeyFramesStates _currentState, _savedState;
-        private Animation _parentAnimation;
+        private KeyFramesStates _currentState, _savedState;
+        private KeyFrames<T> _parent;
+        private Animation _targetAnimation;
         private Animatable _targetControl;
         internal bool _unsubscribe = false;
         double _outputTime = 0d;
@@ -40,9 +47,10 @@ namespace Avalonia.Animation.Keyframes
             DISPOSED
         }
 
-        public void Initialize(Animation animation, Animatable control)
+        public void Initialize(Animation animation, Animatable control, KeyFrames<T> keyframes)
         {
-            _parentAnimation = animation;
+            _parent = keyframes;
+            _targetAnimation = animation;
             _targetControl = control;
 
             _delayTotalFrameCount = (ulong)(animation.Delay.Ticks / Timing.FrameTick.Ticks);
@@ -85,14 +93,14 @@ namespace Avalonia.Animation.Keyframes
                     break;
             }
 
-            _animationDirection = _parentAnimation.PlaybackDirection;
+            _animationDirection = _targetAnimation.PlaybackDirection;
+            _fillMode = _targetAnimation.FillMode;
 
             if (_durationTotalFrameCount > 0)
                 _currentState = KeyFramesStates.DO_DELAY;
             else
                 _currentState = KeyFramesStates.DO_RUN;
 
-             
         }
 
         public void Step(PlayState _playState, Func<double, T> Interpolator)
@@ -109,6 +117,13 @@ namespace Avalonia.Animation.Keyframes
 
         private void InternalStep(PlayState _playState, Func<double, T> Interpolator)
         {
+
+            if (!_gotFirstKFValue)
+            {
+                _firstKFValue = (T)_parent.First().Value;
+                _gotFirstKFValue = true;
+            }
+
             if (_currentState == KeyFramesStates.DISPOSED)
                 throw new InvalidProgramException("This KeyFrames Animation is already disposed.");
 
@@ -132,22 +147,34 @@ namespace Avalonia.Animation.Keyframes
             switch (_currentState)
             {
                 case KeyFramesStates.DO_DELAY:
+
+                    if (_currentIteration == 0
+                     && _fillMode == FillMode.Backward
+                     || _fillMode == FillMode.Both)
+                    {
+                        _targetObserver.OnNext(_firstKFValue);
+                    }
+
                     if (_delayFrameCount > _delayTotalFrameCount)
                     {
                         _currentState = KeyFramesStates.DO_RUN;
                         goto checkstate;
                     }
                     _delayFrameCount++;
+
                     break;
 
                 case KeyFramesStates.DO_RUN:
+                    
                     if (_isReversed)
                         _currentState = KeyFramesStates.RUN_BACKWARDS;
                     else
                         _currentState = KeyFramesStates.RUN_FORWARDS;
+
                     goto checkstate;
 
                 case KeyFramesStates.RUN_FORWARDS:
+
                     if (_durationFrameCount > _durationTotalFrameCount)
                     {
                         _currentState = KeyFramesStates.RUN_COMPLETE;
@@ -160,6 +187,7 @@ namespace Avalonia.Animation.Keyframes
                     goto checkstate;
 
                 case KeyFramesStates.RUN_BACKWARDS:
+                
                     if (_durationFrameCount > _durationTotalFrameCount)
                     {
                         _currentState = KeyFramesStates.RUN_COMPLETE;
@@ -173,7 +201,7 @@ namespace Avalonia.Animation.Keyframes
 
                 case KeyFramesStates.RUN_APPLYVALUE:
 
-                    _easedTime = _parentAnimation.Easing.Ease(_tempDuration);
+                    _easedTime = _targetAnimation.Easing.Ease(_tempDuration);
 
                     _durationFrameCount++;
                     _lastInterpValue = Interpolator(_easedTime);
@@ -217,6 +245,11 @@ namespace Avalonia.Animation.Keyframes
                     goto checkstate;
 
                 case KeyFramesStates.STOP:
+                    if (_fillMode == FillMode.Forward
+                     || _fillMode == FillMode.Both)
+                    {
+                        _targetControl.SetValue(_parent.Property, _lastInterpValue, BindingPriority.Animation);
+                    }
                     _targetObserver.OnCompleted();
                     break;
             }