Brush to Brush Animation

后端 未结 3 1369
夕颜
夕颜 2020-12-09 08:30

I managed to find out how to make a WPF animation - transition between two colors.

It\'s called ColorAnimation and works well.

ColorAnimation animati         


        
相关标签:
3条回答
  • 2020-12-09 09:10

    You just need to use the color animation on the gradient stops of the gradient brush. Here is an example that animates a rectangle gradient using a storyboard.

        <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="GradientBrushAnimation.MainWindow"
        x:Name="Window"
        Title="MainWindow"
        Width="640" Height="480">
        <Window.Resources>
            <Storyboard x:Key="Storyboard1">
                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                    <EasingColorKeyFrame KeyTime="0:0:2" Value="Red"/>
                </ColorAnimationUsingKeyFrames>
                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                    <EasingColorKeyFrame KeyTime="0:0:2" Value="#FF71FF00"/>
                </ColorAnimationUsingKeyFrames>
            </Storyboard>
        </Window.Resources>
        <Window.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
            </EventTrigger>
        </Window.Triggers>
    
        <Grid x:Name="LayoutRoot">
            <Rectangle x:Name="rectangle" Margin="78,102,292,144" Stroke="Black">
                <Rectangle.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="White" Offset="1"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>
        </Grid>
    </Window>
    
    0 讨论(0)
  • 2020-12-09 09:24

    You can animate the color of the brush if you have a template style in which you give the fill brush a name, like so:

    <Rectangle Width="100" Height="100">
      <Rectangle.Fill>
        <SolidColorBrush x:Name="MyAnimatedBrush" Color="Orange" />
      </Rectangle.Fill>
      <Rectangle.Triggers>
    
        <!-- Animates the brush's color to gray
             When the mouse enters the rectangle. -->
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <BeginStoryboard>
            <Storyboard>
              <ColorAnimation
                Storyboard.TargetName="MyAnimatedBrush"
                Storyboard.TargetProperty="Color"
                To="Gray" Duration="0:0:1" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>  
      </Rectangle.Triggers>
    </Rectangle>
    

    As taken from MSDN

    0 讨论(0)
  • 2020-12-09 09:31

    Another possible way is, to create a custom animtion class that animate brushes. I found a simple way to do that by creating a class, derivated from AnimationTimeline. We can override some members in the custom class, among other things the AnimationTimeline.GetCurrentValue method. It returns a value depend on the animation progress and the start- and end value.

    The simplest way is to create a VisualBrush and crossfade the start- with the end value with the Opacity property on a child control. The result is a class like the following:

    public class BrushAnimation : AnimationTimeline
    {
        public override Type TargetPropertyType
        {
            get
            {
                return typeof(Brush);
            }
        }
    
        public override object GetCurrentValue(object defaultOriginValue,
                                               object defaultDestinationValue,
                                               AnimationClock animationClock)
        {
            return GetCurrentValue(defaultOriginValue as Brush,
                                   defaultDestinationValue as Brush,
                                   animationClock);
        }
        public object GetCurrentValue(Brush defaultOriginValue,
                                      Brush defaultDestinationValue,
                                      AnimationClock animationClock)
        {
            if (!animationClock.CurrentProgress.HasValue)
                return Brushes.Transparent;
    
            //use the standard values if From and To are not set 
            //(it is the value of the given property)
            defaultOriginValue = this.From ?? defaultOriginValue;
            defaultDestinationValue = this.To ?? defaultDestinationValue;
    
            if (animationClock.CurrentProgress.Value == 0)
                return defaultOriginValue;
            if (animationClock.CurrentProgress.Value == 1)
                return defaultDestinationValue;
    
            return new VisualBrush(new Border()
            {
                Width = 1,
                Height = 1,
                Background = defaultOriginValue,
                Child = new Border()
                {
                    Background = defaultDestinationValue,
                    Opacity = animationClock.CurrentProgress.Value,
                }
            });
        }
    
        protected override Freezable CreateInstanceCore()
        {
            return new BrushAnimation();
        }
    
        //we must define From and To, AnimationTimeline does not have this properties
        public Brush From
        {
            get { return (Brush)GetValue(FromProperty); }
            set { SetValue(FromProperty, value); }
        }
        public Brush To
        {
            get { return (Brush)GetValue(ToProperty); }
            set { SetValue(ToProperty, value); }
        }
    
        public static readonly DependencyProperty FromProperty =
            DependencyProperty.Register("From", typeof(Brush), typeof(BrushAnimation));
        public static readonly DependencyProperty ToProperty =
            DependencyProperty.Register("To", typeof(Brush), typeof(BrushAnimation));
    }
    

    You can use it as always in XAML:

    <EventTrigger RoutedEvent="Loaded">
        <BeginStoryboard>
            <Storyboard >
                <local:BrushAnimation Storyboard.TargetName="border"
                                      Storyboard.TargetProperty="Background" 
                                      Duration="0:0:5" From="Red" 
                                      RepeatBehavior="Forever" AutoReverse="True" >
                    <local:BrushAnimation.To>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FF00FF2E" Offset="0.005"/>
                            <GradientStop Color="#FFC5FF00" Offset="1"/>
                            <GradientStop Color="Blue" Offset="0.43"/>
                        </LinearGradientBrush>
                    </local:BrushAnimation.To>
                </local:BrushAnimation>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
    

    or in code behind:

    var animation = new BrushAnimation
    {
        From = Brushes.Red,
        To = new LinearGradientBrush (Colors.Green, Colors.Yellow, 45),
        Duration = new Duration(TimeSpan.FromSeconds(5)),
    };
    animation.Completed += new EventHandler(animation_Completed);
    Storyboard.SetTarget(animation, border);
    Storyboard.SetTargetProperty(animation, new PropertyPath("Background"));
    
    var sb = new Storyboard();
    sb.Children.Add(animation);
    sb.Begin();
    

    It is also possible to extend the BrushAnimation with constructor overloads etc., so it looks like a .NET given animation type.

    0 讨论(0)
提交回复
热议问题