1

我有这个按钮:

在此处输入图像描述

由以下 XAML 代码组成:

<Style TargetType="{x:Type Button}" x:Key="GreenButtonStyle" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Foreground" Value="#fff" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border" BorderThickness="1" BorderBrush="#446c06" CornerRadius="3" Background="{TemplateBinding Background}">
                    <Border BorderBrush="#55ffffff" BorderThickness="1" CornerRadius="3" Padding="6,4">
                        <Grid>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="contentShadow" Style="{StaticResource ShadowStyle}">
                                <ContentPresenter.RenderTransform>
                                    <TranslateTransform X="1.0" Y="1.0" />
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content" />
                        </Grid>
                    </Border>
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter Property="Background">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                    <GradientStop Color="#aae64b" Offset="0"/>
                                    <GradientStop Color="#7eb922" Offset="0.16"/>
                                    <GradientStop Color="#6aa016" Offset="0.57"/>
                                    <GradientStop Color="#649714" Offset="0.86"/>
                                    <GradientStop Color="#7eb922" Offset="1"/>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>

                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background">
                            <Setter.Value>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                    <GradientStop Color="#bbf75c" Offset="0"/>
                                    <GradientStop Color="#8fba33" Offset="0.16"/>
                                    <GradientStop Color="#7bb127" Offset="0.57"/>
                                    <GradientStop Color="#75a825" Offset="0.86"/>
                                    <GradientStop Color="#8fca33" Offset="1"/>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>

                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" >
                            <Setter.Value>
                                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0" >
                                    <GradientStop Color="#aae64b" Offset="0"/>
                                    <GradientStop Color="#7eb922" Offset="0.16"/>
                                    <GradientStop Color="#6aa016" Offset="0.57"/>
                                    <GradientStop Color="#649714" Offset="0.86"/>
                                    <GradientStop Color="#7eb922" Offset="1"/>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>

                        <Setter TargetName="content" Property="RenderTransform" >
                            <Setter.Value>
                                <TranslateTransform Y="1.0" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

一切都很好,除了我想在鼠标状态(按下+正常+悬停)之间进行转换/动画。

我在网上找到了一些指南,它们为每个渐变停止属性设置动画,但我不想这样做。我只是想在渐变之间进行直接过渡。

有没有一种简单的方法可以在不为每个渐变停止属性设置动画的情况下做到这一点?

4

2 回答 2

2

正如 Erno 所指出的,没有LinearGradientAnimation,但它可以以与ColorAnimation作品相同的方式创建。如果我们查看 的实现,ColorAnimation我们会发现它使用了辅助函数,例如

  • AddColor(Color value1, Color value2)
  • SubtractColor(Color value1, Color value2)
  • ScaleColor(Color value, double factor)
  • InterpolateColor(Color from, Color to, double progress)

要创建 aLinearGradientAnimation我们需要相同的功能,但使用 forLinearGradientBrush而不是Color. 我创建了这样一个动画,它似乎按预期工作。一个要求是ToFromvalue 具有相同数量的GradientStops

可以这样使用

<Storyboard>
    <ani:LinearGradientAnimation Storyboard.TargetProperty="Background" 
                                 Duration="0:0:0.2"
                                 From="{StaticResource NormalBrush}"
                                 To="{StaticResource MouseOverBrush}"/>
</Storyboard>

在你的情况下,它会是这样的..

<LinearGradientBrush x:Key="NormalBrush" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#aae64b" Offset="0"/>
    <GradientStop Color="#7eb922" Offset="0.16"/>
    <GradientStop Color="#6aa016" Offset="0.57"/>
    <GradientStop Color="#649714" Offset="0.86"/>
    <GradientStop Color="#7eb922" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="MouseOverBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="#bbf75c" Offset="0"/>
    <GradientStop Color="#8fba33" Offset="0.16"/>
    <GradientStop Color="#7bb127" Offset="0.57"/>
    <GradientStop Color="#75a825" Offset="0.86"/>
    <GradientStop Color="#8fca33" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,1" EndPoint="0,0" >
    <GradientStop Color="#aae64b" Offset="0"/>
    <GradientStop Color="#7eb922" Offset="0.16"/>
    <GradientStop Color="#6aa016" Offset="0.57"/>
    <GradientStop Color="#649714" Offset="0.86"/>
    <GradientStop Color="#7eb922" Offset="1"/>
</LinearGradientBrush>

<Style x:Key="GreenButtonStyle"
        TargetType="{x:Type Button}"               
        BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Foreground" Value="#fff" />
    <Setter Property="Background" Value="{StaticResource NormalBrush}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border" BorderThickness="1" BorderBrush="#446c06" CornerRadius="3" Background="{TemplateBinding Background}">
                    <Border BorderBrush="#55ffffff" BorderThickness="1" CornerRadius="3" Padding="6,4">
                        <Grid>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="contentShadow">
                                <ContentPresenter.RenderTransform>
                                    <TranslateTransform X="1.0" Y="1.0" />
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content" />
                        </Grid>
                    </Border>
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ani:LinearGradientAnimation Storyboard.TargetProperty="Background" 
                                                                    Duration="0:0:0.2"
                                                                    To="{StaticResource MouseOverBrush}"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="mouseUpStoryboard"/>
                            <BeginStoryboard x:Name="mouseLeaveStoryboard">
                                <Storyboard>
                                    <ani:LinearGradientAnimation Storyboard.TargetProperty="Background" 
                                                                    Duration="0:0:0.2"
                                                                    To="{StaticResource NormalBrush}"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>

                    <Trigger Property="IsPressed" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ani:LinearGradientAnimation Storyboard.TargetProperty="Background" 
                                                                Duration="0:0:0.2"
                                                                To="{StaticResource PressedBrush}"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard x:Name="mouseUpStoryboard">
                                <Storyboard>
                                    <ani:LinearGradientAnimation Storyboard.TargetProperty="Background" 
                                                                Duration="0:0:0.2"
                                                                To="{StaticResource MouseOverBrush}"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                        <Setter TargetName="content" Property="RenderTransform" >
                            <Setter.Value>
                                <TranslateTransform Y="1.0" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

在这里上传了一个小示例应用程序LinearGradientAnimationLinearGradientAnimationDemo.zip

线性渐变动画.cs

public class LinearGradientAnimation : AnimationTimeline
{
    #region Dependency Properties

    public static readonly DependencyProperty FromProperty =
         DependencyProperty.Register("From",
                                     typeof(LinearGradientBrush),
                                     typeof(LinearGradientAnimation),
                                     new PropertyMetadata(null, AnimationFunction_Changed));

    public static readonly DependencyProperty ToProperty =
        DependencyProperty.Register("To",
                                    typeof(LinearGradientBrush),
                                    typeof(LinearGradientAnimation),
                                    new PropertyMetadata(null, AnimationFunction_Changed));

    public static readonly DependencyProperty ByProperty = 
        DependencyProperty.Register("By",
                                    typeof(LinearGradientBrush),
                                    typeof(LinearGradientAnimation),
                                    new PropertyMetadata(null, AnimationFunction_Changed));

    public static readonly DependencyProperty EasingFunctionProperty =
        DependencyProperty.Register("EasingFunction",
                                    typeof(IEasingFunction),
                                    typeof(LinearGradientAnimation));

    private static void AnimationFunction_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        LinearGradientAnimation linearGradientAnimation = (LinearGradientAnimation)d;
        linearGradientAnimation._isAnimationFunctionValid = false;
    }

    #endregion // Dependency Properties

    #region Private Fields

    private LinearGradientBrush[] _keyValues;
    private AnimationType _animationType;
    private bool _isAnimationFunctionValid;

    #endregion // Private Fields

    #region Constructor

    public LinearGradientAnimation()
    {
    }

    public LinearGradientAnimation(LinearGradientBrush toValue, Duration duration)
        : this()
    {
        this.To = toValue;
        base.Duration = duration;
    }

    public LinearGradientAnimation(LinearGradientBrush toValue, Duration duration, FillBehavior fillBehavior)
        : this()
    {
        this.To = toValue;
        base.Duration = duration;
        base.FillBehavior = fillBehavior;
    }

    public LinearGradientAnimation(LinearGradientBrush fromValue, LinearGradientBrush toValue, Duration duration)
        : this()
    {
        this.From = fromValue;
        this.To = toValue;
        base.Duration = duration;
    }

    public LinearGradientAnimation(LinearGradientBrush fromValue, LinearGradientBrush toValue, Duration duration, FillBehavior fillBehavior)
        : this()
    {
        this.From = fromValue;
        this.To = toValue;
        base.Duration = duration;
        base.FillBehavior = fillBehavior;
    }

    #endregion // Constructor

    #region Properties

    public LinearGradientBrush From
    {
        get { return (LinearGradientBrush)base.GetValue(LinearGradientAnimation.FromProperty); }
        set { base.SetValue(LinearGradientAnimation.FromProperty, value); }
    }

    public LinearGradientBrush To
    {
        get { return (LinearGradientBrush)base.GetValue(LinearGradientAnimation.ToProperty); }
        set { base.SetValue(LinearGradientAnimation.ToProperty, value); }
    }

    public LinearGradientBrush By
    {
        get { return (LinearGradientBrush)base.GetValue(LinearGradientAnimation.ByProperty); }
        set { base.SetValue(LinearGradientAnimation.ByProperty, value); }
    }

    public IEasingFunction EasingFunction
    {
        get { return (IEasingFunction)base.GetValue(LinearGradientAnimation.EasingFunctionProperty); }
        set { base.SetValue(LinearGradientAnimation.EasingFunctionProperty, value); }
    }

    public bool IsAdditive
    {
        get { return (bool)base.GetValue(AnimationTimeline.IsAdditiveProperty); }
        set { base.SetValue(AnimationTimeline.IsAdditiveProperty, value); }
    }

    public bool IsCumulative
    {
        get { return (bool)base.GetValue(AnimationTimeline.IsCumulativeProperty); }
        set { base.SetValue(AnimationTimeline.IsCumulativeProperty, value); }
    }

    #endregion // Properties

    #region Private Methods

    protected LinearGradientBrush GetCurrentValueCore(LinearGradientBrush defaultOriginValue, LinearGradientBrush defaultDestinationValue, AnimationClock animationClock)
    {
        if (!this._isAnimationFunctionValid)
        {
            this.ValidateAnimationFunction();
        }
        double num = animationClock.CurrentProgress.Value;
        IEasingFunction easingFunction = this.EasingFunction;
        if (easingFunction != null)
        {
            num = easingFunction.Ease(num);
        }
        LinearGradientBrush brush = null;
        LinearGradientBrush brush2 = null;
        LinearGradientBrush value = null;
        LinearGradientBrush value2 = null;
        switch (this._animationType)
        {
        case AnimationType.Automatic:
            brush = defaultOriginValue;
            brush2 = defaultDestinationValue;
            value = GetDefaultLinearGradientBrush(brush);
            value2 = GetDefaultLinearGradientBrush(brush);
            break;
        case AnimationType.From:
            brush = this._keyValues[0];
            brush2 = defaultDestinationValue;
            value = GetDefaultLinearGradientBrush(brush);
            value2 = GetDefaultLinearGradientBrush(brush);
            break;
        case AnimationType.To:
            brush = defaultOriginValue;
            brush2 = this._keyValues[0];
            value = GetDefaultLinearGradientBrush(brush2);
            value2 = GetDefaultLinearGradientBrush(brush2);
            break;
        case AnimationType.By:
            brush2 = this._keyValues[0];
            value2 = defaultOriginValue;
            value = GetDefaultLinearGradientBrush(brush2);
            value2 = GetDefaultLinearGradientBrush(brush2);
            break;
        case AnimationType.FromTo:
            brush = this._keyValues[0];
            brush2 = this._keyValues[1];
            value = GetDefaultLinearGradientBrush(brush);
            value2 = GetDefaultLinearGradientBrush(brush);
            if (this.IsAdditive)
            {
                value2 = defaultOriginValue;
            }
            break;
        case AnimationType.FromBy:
            brush = this._keyValues[0];
            brush2 = AddLinearGradientBrush(this._keyValues[0], this._keyValues[1]);
            value = GetDefaultLinearGradientBrush(brush);
            value2 = GetDefaultLinearGradientBrush(brush);
            if (this.IsAdditive)
            {
                value2 = defaultOriginValue;
            }
            break;
        }

        if (this.IsCumulative)
        {
            double num2 = (double)(animationClock.CurrentIteration - 1).Value;
            if (num2 > 0.0)
            {
                LinearGradientBrush value3 = SubtractLinearGradientBrush(brush2, brush);
                value = ScaleLinearGradientBrush(value3, num2);
            }
        }
        LinearGradientBrush returnBrush = AddLinearGradientBrush(value2, AddLinearGradientBrush(value, InterpolateGradientBrush(brush, brush2, num)));
        return returnBrush;
    }

    private LinearGradientBrush GetDefaultLinearGradientBrush(LinearGradientBrush brush)
    {
        LinearGradientBrush returnBrush = new LinearGradientBrush();
        returnBrush.StartPoint = default(Point);
        returnBrush.EndPoint = default(Point);
        for (int i = 0; i < brush.GradientStops.Count; i++)
        {
            returnBrush.GradientStops.Add(new GradientStop(default(Color), default(double)));
        }
        return returnBrush;
    }

    private void ValidateAnimationFunction()
    {
        this._animationType = AnimationType.Automatic;
        this._keyValues = null;
        if (this.From != null)
        {
            if (this.To != null)
            {
                this._animationType = AnimationType.FromTo;
                this._keyValues = new LinearGradientBrush[2];
                this._keyValues[0] = this.From;
                this._keyValues[1] = this.To;
            }
            else
            {
                if (this.By != null)
                {
                    this._animationType = AnimationType.FromBy;
                    this._keyValues = new LinearGradientBrush[2];
                    this._keyValues[0] = this.From;
                    this._keyValues[1] = this.By;
                }
                else
                {
                    this._animationType = AnimationType.From;
                    this._keyValues = new LinearGradientBrush[1];
                    this._keyValues[0] = this.From;
                }
            }
        }
        else
        {
            if (this.To != null)
            {
                this._animationType = AnimationType.To;
                this._keyValues = new LinearGradientBrush[1];
                this._keyValues[0] = this.To;
            }
            else
            {
                if (this.By != null)
                {
                    this._animationType = AnimationType.By;
                    this._keyValues = new LinearGradientBrush[1];
                    this._keyValues[0] = this.By;
                }
            }
        }
        this._isAnimationFunctionValid = true;
    }

    #endregion // Private Methods

    #region AnimationTimeline / Freezable Members

    public override Type TargetPropertyType
    {
        get { return typeof(LinearGradientBrush); }
    }

    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
    {
        if (defaultOriginValue == null)
        {
            throw new ArgumentNullException("defaultOriginValue");
        }
        if (defaultDestinationValue == null)
        {
            throw new ArgumentNullException("defaultDestinationValue");
        }
        return this.GetCurrentValue((LinearGradientBrush)defaultOriginValue, (LinearGradientBrush)defaultDestinationValue, animationClock);
    }

    public LinearGradientBrush GetCurrentValue(LinearGradientBrush defaultOriginValue, LinearGradientBrush defaultDestinationValue, AnimationClock animationClock)
    {
        base.ReadPreamble();
        if (animationClock == null)
        {
            throw new ArgumentNullException("animationClock");
        }
        if (animationClock.CurrentState == ClockState.Stopped)
        {
            return defaultDestinationValue;
        }
        return this.GetCurrentValueCore(defaultOriginValue, defaultDestinationValue, animationClock);
    }

    public new LinearGradientAnimation Clone()
    {
        return (LinearGradientAnimation)base.Clone();
    }

    protected override Freezable CreateInstanceCore()
    {
        return new LinearGradientAnimation();
    }

    #endregion // AnimationTimeline / Freezable Members

    #region Helper Methods

    internal static LinearGradientBrush AddLinearGradientBrush(LinearGradientBrush brush1, LinearGradientBrush brush2)
    {
        LinearGradientBrush gradientBrush = new LinearGradientBrush();
        gradientBrush.StartPoint = AddPoint(brush1.StartPoint, brush2.StartPoint);
        gradientBrush.EndPoint = AddPoint(brush1.EndPoint, brush2.EndPoint);
        for (int i = 0; i < brush1.GradientStops.Count; i++)
        {
            GradientStop gradientStop1 = brush1.GradientStops[i];
            GradientStop gradientStop2 = brush2.GradientStops[i];

            Color color = AddColor(gradientStop1.Color, gradientStop2.Color);
            double offset = AddDouble(gradientStop1.Offset, gradientStop2.Offset);

            gradientBrush.GradientStops.Add(new GradientStop(color, offset));
        }
        return gradientBrush;
    }
    internal static LinearGradientBrush SubtractLinearGradientBrush(LinearGradientBrush brush1, LinearGradientBrush brush2)
    {
        LinearGradientBrush gradientBrush = new LinearGradientBrush();
        gradientBrush.StartPoint = SubtractPoint(brush1.StartPoint, brush2.StartPoint);
        gradientBrush.EndPoint = SubtractPoint(brush1.EndPoint, brush2.EndPoint);
        for (int i = 0; i < brush1.GradientStops.Count; i++)
        {
            GradientStop gradientStop1 = brush1.GradientStops[i];
            GradientStop gradientStop2 = brush2.GradientStops[i];

            Color color = SubtractColor(gradientStop1.Color, gradientStop2.Color);
            double offset = SubtractDouble(gradientStop1.Offset, gradientStop2.Offset);

            gradientBrush.GradientStops.Add(new GradientStop(color, offset));
        }
        return gradientBrush;
    }
    internal static LinearGradientBrush ScaleLinearGradientBrush(LinearGradientBrush value, double factor)
    {
        LinearGradientBrush gradientBrush = new LinearGradientBrush();
        gradientBrush.StartPoint = ScalePoint(value.StartPoint, factor);
        gradientBrush.EndPoint = ScalePoint(value.EndPoint, factor);
        for (int i = 0; i < value.GradientStops.Count; i++)
        {
            Color color = ScaleColor(value.GradientStops[i].Color, factor);
            double offset = ScaleDouble(value.GradientStops[i].Offset, factor);
            gradientBrush.GradientStops.Add(new GradientStop(color, offset));
        }
        return gradientBrush;
    }
    internal static LinearGradientBrush InterpolateGradientBrush(LinearGradientBrush from, LinearGradientBrush to, double progress)
    {
        LinearGradientBrush gradientBrush = new LinearGradientBrush();
        gradientBrush.StartPoint = InterpolatePoint(from.StartPoint, to.StartPoint, progress);
        gradientBrush.EndPoint = InterpolatePoint(from.EndPoint, to.EndPoint, progress);
        for (int i = 0; i < from.GradientStops.Count; i++)
        {
            Color color = InterpolateColor(from.GradientStops[i].Color, to.GradientStops[i].Color, progress);
            double offset = InterpolateDouble(from.GradientStops[i].Offset, to.GradientStops[i].Offset, progress);
            gradientBrush.GradientStops.Add(new GradientStop(color, offset));
        }
        return gradientBrush;
    }
    internal static Color AddColor(Color value1, Color value2)
    {
        return value1 + value2;
    }
    internal static Color SubtractColor(Color value1, Color value2)
    {
        return value1 - value2;
    }
    internal static Color ScaleColor(Color value, double factor)
    {
        return value * (float)factor;
    }
    internal static Color InterpolateColor(Color from, Color to, double progress)
    {
        return from + (to - from) * (float)progress;
    }

    internal static double AddDouble(double value1, double value2)
    {
        return value1 + value2;
    }
    internal static double SubtractDouble(double value1, double value2)
    {
        return value1 - value2;
    }
    internal static double ScaleDouble(double value, double factor)
    {
        return value * factor;
    }
    internal static double InterpolateDouble(double from, double to, double progress)
    {
        return from + (to - from) * progress;
    }

    internal static Point AddPoint(Point value1, Point value2)
    {
        return new Point(value1.X + value2.X, value1.Y + value2.Y);
    }
    internal static Point SubtractPoint(Point value1, Point value2)
    {
        return new Point(value1.X - value2.X, value1.Y - value2.Y);
    }
    internal static Point ScalePoint(Point value, double factor)
    {
        return new Point(value.X * factor, value.Y * factor);
    }
    internal static Point InterpolatePoint(Point from, Point to, double progress)
    {
        return from + (to - from) * progress;
    }

    #endregion // Helper Methods
}

你还需要

internal enum AnimationType : byte
{
    Automatic,
    From,
    To,
    By,
    FromTo,
    FromBy
}
于 2012-05-27T12:55:54.593 回答
1

您可以叠加两个矩形,每个矩形都填充有渐变,并为顶部矩形的不透明度设置动画。

这可能看起来不错或不好看,具体取决于您对过渡的期望。

如果你喜欢冒险:没有 LinearGradientAnimation 但你可以做到......

于 2012-05-26T17:34:22.117 回答