精华内容
下载资源
问答
  • WPF圆形动画按钮

    2020-05-15 14:14:04
    点击一级按钮,弹出二级按钮点击二级按钮,显示图片;图片可滚动显示。 核心代码: private void Get_Buttons(int BtnNumber) { int a = 0; #region 新代码 foreach (var item in dataList) { FileName...

    效果图:

    点击一级按钮,弹出二级按钮,点击二级按钮,显示图片;图片可滚动显示。

     

    左键可实现拖拽功能,右键触发点击事件。可自行更改

    核心代码: 

            private void Get_Buttons(int BtnNumber)
            {
                int a = 0;
                #region 新代码
                foreach (var item in dataList)
                {
                    FileName = DataFiles[a].Substring(DataFiles[a].LastIndexOf('\\') + 1);
                    a++;
                    Image image = new Image();
                    image.Source = SetImageSource(FileName + ".png");
                    image.Tag = FileName;
                    image.Width = image.Height = iconWidthAndHeight;
                    image.SetValue(Canvas.LeftProperty, item.xPoint);
                    image.SetValue(Canvas.TopProperty, item.yPoint);
                    MenuCanvas.Children.Add(image);
                    image.MouseLeftButtonDown += Image_MouseLeftButtonDown;
                    if (a == BtnNumber)
                    {
                        break;
                    }
                }
                #endregion
            }

            private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                Image img = sender as Image;

                DataFiles = Directory.GetDirectories(Environment.CurrentDirectory + "\\内容\\"+ img.Tag);
                MenuCanvas.Children.Clear();
                Get_Buttons1(DataFiles.Length,img.Tag.ToString());
                viewHuanDong();
            }
            string fileName;
            private void Get_Buttons1(int BtnNumber,string FileName)
            {
                fileName = FileName;
                int a = 0;
                #region 新代码
                foreach (var item in dataList)
                {
                    ImgName = DataFiles[a].Substring(DataFiles[a].LastIndexOf('\\') + 1);
                    a++;
                    Image image = new Image();
                    image.Source = SetImageSource(ImgName + ".png");
                    image.Tag = ImgName;
                    
                    image.Width = image.Height = iconWidthAndHeight;
                    image.SetValue(Canvas.LeftProperty, item.xPoint);
                    image.SetValue(Canvas.TopProperty, item.yPoint);
                    MenuCanvas.Children.Add(image);
                    image.MouseLeftButtonDown += Image_MouseLeftButtonDown1; ;
                    if (a == BtnNumber)
                    {
                        break;
                    }
                }
                #endregion
            }

            private void Image_MouseLeftButtonDown1(object sender, MouseButtonEventArgs e)
            {
                Grid_Canvas.Children.Clear();
                Image img = sender as Image;
                Canvas canvas = new Canvas();
                ScrollViewer scroll = new ScrollViewer();
                WrapPanel wrap = new WrapPanel();
                ImgFiles = Directory.GetFiles(Environment.CurrentDirectory + "\\内容\\" + fileName + "\\" + img.Tag);
                foreach(var item in ImgFiles)
                {
                    Image img1 = new Image();
                    img1.Source=new BitmapImage( new Uri(item, UriKind.RelativeOrAbsolute));
                    img1.Height = 600;
                    img1.Width = 800;
                    img1.Stretch = Stretch.Fill;
                    wrap.Children.Add(img1);
                }
                Point p = Mouse.GetPosition(e.Source as Grid);
                scroll.Content = wrap;
                scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
                scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
                scroll.Width = 800;
                canvas.Children.Add(scroll);
                canvas.Width = 800;
                canvas.Height = 600;
                canvas.VerticalAlignment = VerticalAlignment.Top;
                canvas.HorizontalAlignment = HorizontalAlignment.Left;
                canvas.Margin = new Thickness(p.X, p.Y, 0, 0);
                Grid_Canvas.Children.Add(canvas);

                canvasHuanDong(canvas);

            }
    下载地址:https://download.csdn.net/download/qq_29098553/12423196

    展开全文
  • WPF 动画闪烁效果

    2021-01-13 13:19:45
    WPF 动画闪烁效果 一、按钮外边缘呼吸闪烁 点击触发效果; 代码: <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x=...

    WPF 动画闪烁效果

    一、按钮外边缘呼吸闪烁
    在这里插入图片描述
    点击触发效果;
    代码:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.Resources>
            <Style x:Key="ResourcesButtonStyle" TargetType="{x:Type FrameworkElement}" >
                <Setter Property="Width" Value="60"/>
                <Setter Property="Height" Value="40"/>
                <Setter Property="Effect">
                    <Setter.Value>
                        <DropShadowEffect x:Name="OSE" BlurRadius="10" 
                                          Color="Lime" Direction="0"   
                                          Opacity="1" 
                                          RenderingBias="Performance" 
                                          ShadowDepth="0" >
                            <Storyboard.TargetProperty>
                                BlurRadius
                            </Storyboard.TargetProperty>
                        </DropShadowEffect>
                    </Setter.Value>
    
                </Setter>
                <Style.Triggers>
                    <EventTrigger RoutedEvent="GotFocus">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation 
                      Storyboard.TargetProperty="(FrameworkElement.Effect).(DropShadowEffect.BlurRadius)" 
                      From="0" To="100" 
                      BeginTime="00:00:00" Duration="00:00:01" 
                      AutoReverse="True"  RepeatBehavior="Forever"/>
    
                                <ColorAnimationUsingKeyFrames 
                      Storyboard.TargetProperty="(FrameworkElement.Effect).(DropShadowEffect.Color)"
                      RepeatBehavior="Forever" AutoReverse="True">
                                    <EasingColorKeyFrame KeyTime="0" Value="Yellow"/>
                                    <EasingColorKeyFrame KeyTime="0:0:0.4" Value="Purple"/>
                                    <EasingColorKeyFrame KeyTime="0:0:0.8" Value="Green"/>
                                    <EasingColorKeyFrame KeyTime="0:0:1.2" Value="DarkCyan"/>
                                    <EasingColorKeyFrame KeyTime="0:0:1.6" Value="Black"/>
                                    <EasingColorKeyFrame KeyTime="0:0:2.0" Value="OrangeRed"/>
                                    <EasingColorKeyFrame KeyTime="0:0:2.4" Value="Violet"/>
                                    <EasingColorKeyFrame KeyTime="0:0:2.8" Value="CornflowerBlue"/>
                                    <EasingColorKeyFrame KeyTime="0:0:3.2" Value="Lime"/>
                                    <EasingColorKeyFrame KeyTime="0:0:3.6" Value="Azure"/>
                                    <EasingColorKeyFrame KeyTime="0:0:4.0" Value="Turquoise"/>
                                    <EasingColorKeyFrame KeyTime="0:0:4.4" Value="Tomato"/>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
        <Grid>
            <Button Content="Hello" Background="#007ACC" Height="30" Width="50" Style="{StaticResource ResourcesButtonStyle}"/>
        </Grid>
    </Window>
    

    二、实心圆颜色呼吸渐变
    效果:
    在这里插入图片描述
    代码:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.Resources>
            <Storyboard x:Key="OnLoaded" RepeatBehavior="Forever" AutoReverse="True"  >
                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Ellipse">
                    <EasingColorKeyFrame KeyTime="0:0:1" Value="#990033"/>
                </ColorAnimationUsingKeyFrames>
            </Storyboard>
        </Window.Resources>
        <Window.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard  Storyboard="{StaticResource OnLoaded}"/>
            </EventTrigger>
        </Window.Triggers>
        <Grid Background="White">
            <Ellipse x:Name="Ellipse" Height="20" Width="20" Fill="#FF6666" >
                <Ellipse.Effect>
                    <DropShadowEffect Opacity="1" ShadowDepth="0" Color="#FF6666" BlurRadius="200" Direction="10"></DropShadowEffect>
                </Ellipse.Effect>
            </Ellipse>
        </Grid>
    </Window>
    

    三、TextBlock字体呼吸闪烁
    在这里插入图片描述
    代码:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
    
        <Grid Background="White">
            <TextBlock Text="Hello!" FontSize="48" Foreground="#ED4646" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Medium" x:Name="TextBlockRecording">
                <TextBlock.Triggers>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                        <BeginStoryboard>
                            <Storyboard BeginTime="0:0:0" Duration="0:0:4" AutoReverse="True" RepeatBehavior="Forever">
                                <ColorAnimation From="#ED4646" To="#F0F2F7" Duration="0:0:2" RepeatBehavior="Forever" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="TextBlockRecording">
                                </ColorAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </TextBlock.Triggers>
            </TextBlock>
        </Grid>
    </Window>
    

    Storyboard类属性介绍:
    AccelerationRatio :获取或设置一个值,该值指定在将时间消逝从零加速到其最大速率的过程中所占用时间线的 Duration 的百分比。 (继承自 Timeline)
    AutoReverse :获取或设置一个值,该值指示时间线在完成向前迭代后是否按相反的顺序播放。 (继承自 Timeline)
    BeginTime :获取或设置此 Timeline 应开始的时间。 (继承自 Timeline)
    CanFreeze :获取一个值,该值指示是否可将对象变为不可修改。 (继承自 Freezable)
    Children :获取或设置 TimelineGroup 的直接子 Timeline 对象的集合。 (继承自 TimelineGroup)
    DecelerationRatio :获取或设置一个值,该值指定在将时间消逝从其最大速率减速到零的过程中所占用时间线的 Duration 的百分比。 (继承自 Timeline)
    DependencyObjectType :获取对此实例的 CLR 类型进行包装的 DependencyObjectType。 (继承自 DependencyObject)
    Dispatcher :获取与此 Dispatcher 关联的 DispatcherObject。 (继承自 DispatcherObject)
    Duration :获取或设置此时间线播放的时间长度,而不是计数重复。 (继承自 Timeline)
    FillBehavior :获取或设置一个值,该值指定 Timeline 在到达其有效期末尾后的行为。 (继承自 Timeline)
    HasAnimatedProperties :获取一个值,该值指示一个或多个 AnimationClock 对象是否与此对象的任何依赖项属性相关联。 (继承自 Animatable)
    IsFrozen :获取一个值,该值指示对象当前是否可修改。 (继承自 Freezable)
    IsSealed :获取一个值,该值指示此实例当前是否为密封的(只读)。 (继承自 DependencyObject)
    Name :获取或设置此 Timeline 的名称。 (继承自 Timeline)
    RepeatBehavior :获取或设置此时间线的重复行为。 (继承自 Timeline)
    SlipBehavior :获取或设置一个值,该值指定在其中一个或多个 Timeline 子级滑动时此时间线的行为方式。 (继承自 ParallelTimeline)
    SpeedRatio :获取或设置此 Timeline 的时间相对于其父级的前进速率。 (继承自 Timeline)

    展开全文
  • 界面上的按钮为两种,一是点击会爆发出微粒,二是点击会出现环形圆圈警告模样。 按钮之间的碰撞及与边界、移动距离及速度的关系受滚动条参数的控制, 代码组织: 文件解释: ParticleEffectExamples.xaml实现以上...
        

    ParticleEffets例子效果

    clipboard.png
    实现效果:

    1. 界面上的按钮为两种,一是点击会爆发出微粒,二是点击会出现环形圆圈警告模样。
    2. 按钮之间的碰撞及与边界、移动距离及速度的关系受滚动条参数的控制,

    代码组织:
    clipboard.png
    类关系图

    文件解释:

    clipboard.png

    1. ParticleEffectExamples.xaml实现以上界面的文件,包括调参数Slider控件、包含按钮的自定义FireworkEffect、SonicEffect控件及容器MagnitismCanvas控件
    2. OverlayRenderDecoratorOverlayVisual.cs继承DrawingVisual类,实现管理是否需要当前Visual类的呈现执行命中测试
    3. OverlayRenderDecorator.cs中 重载呈现装饰类OverlayRenderDecorator继承框架类FrameworkElement,聚集上面的OverlayRenderDecoratorOverlayVisual字段、可视化集合类VisualCollection、作为子内容UIElement类的引用。实现添加逻辑内容按钮并点击时会呈现由子类实现的具体呈现内容,如爆发微粒,警告模样呈现。
    4. FireworkEffect.cs文件继承以上装饰类OverlayRenderDecorator实现爆发微粒绘图的每帧呈现,由鼠标点击触发及爆发微粒的每帧可视化呈现 来实现。其中包含微粒的生成、数量、随机出现下落位置、消失及更新。
    5. SonicEffect.cs文件同上,触发圆环的绘制,包含圆环的数量、大小等。
    6. MagnitismCanvas.cs文件继承画布Canvas,设置三个参数:摇摆幅度Drag、边界作用力BorderForce、子项间的相互作用力ChildForce
    7. ParticleEffectsTimeTracker.cs文件提供基本的时间增量驱动,对MagnitismCanvas来说,获取每帧的时间间隔与内容项的位移参数;对FireworkEffect来说也提供帧间时间值,判断是否大于存在时间;对SonicEffet来说暂时未确定,因为更改附件属性RingDelay未起作用。

    界面xaml:

    <Canvas x:Name="PageCanvas">
      <ae:MagnitismCanvas x:Name="MagCanvas" Drag="0.8" BorderForce="1000" ChildForce="100" 
                DataContext="{Binding ElementName=PageCanvas}" Width="{Binding Path=ActualWidth}" Height="{Binding Path=ActualHeight}">
        <ae:FireworkEffect Canvas.Top="100" Canvas.Left="100">
          <ae:FireworkEffect.Child>
            <Button>Click For Fireworks</Button>
          </ae:FireworkEffect.Child>
        </ae:FireworkEffect>
        <ae:SonicEffect Canvas.Top="200" Canvas.Left="200" RingThickness="10" RingRadius="15"  RingDelay="0:0:2" RingColor="#22553366">
          <ae:SonicEffect.Child>
            <Button>Click For Sonic burst</Button>
          </ae:SonicEffect.Child>
        </ae:SonicEffect>

    OverlayRenderDecoratorOverlayVisual:

    /// <summary>
    ///     This class is used internally to delegate it's rendering to the parent OverlayRenderDecorator.
    /// </summary>
    internal class OverlayRenderDecoratorOverlayVisual : DrawingVisual
    {
        internal bool IsHitTestVisible { get; set; } = false;
        //dont hit test, these are just overlay graphics
        protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters)
        {
            if (IsHitTestVisible)
                return base.HitTestCore(hitTestParameters);
            return null;
        }
    
        //dont hit test, these are just overlay graphics
        protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
        {
            if (IsHitTestVisible)
                return base.HitTestCore(hitTestParameters);
            return null;
        }
    }
    /// <summary>
        ///     OverlayRenderDecorator provides a simple overlay graphics mechanism similar
        ///     to OnRender called OnOverlayRender
        /// </summary>
        [ContentProperty("Child")]
        public class OverlayRenderDecorator : FrameworkElement
        {
            //this will be a visual child, but not a logical child.  as the last child, it can 'overlay' graphics
            // by calling back to us with OnOverlayRender
            private readonly OverlayRenderDecoratorOverlayVisual _overlayVisual;
            private readonly VisualCollection _vc;
            //the only logical child
            private UIElement _child;
            //-------------------------------------------------------------------
            //
            //  Constructors
            //
            //-------------------------------------------------------------------
    
            #region Constructors
    
            /// <summary>
            ///     Default constructor
            /// </summary>
            public OverlayRenderDecorator()
            {
                _overlayVisual = new OverlayRenderDecoratorOverlayVisual();
    
                _vc = new VisualCollection(this) {_overlayVisual};
                
                //insert the overlay element into the visual tree
            }
    
            #endregion
    
            //-------------------------------------------------------------------
            //
            //  Public Properties
            //
            //-------------------------------------------------------------------
    
            #region Public Properties
    
            /// <summary>
            ///     Enables/Disables hit testing on the overlay visual
            /// </summary>
            public bool IsOverlayHitTestVisible
            {
                get
                {
                    if (_overlayVisual != null)
                        return _overlayVisual.IsHitTestVisible;
                    return false;
                }
                set
                {
                    if (_overlayVisual != null)
                        _overlayVisual.IsHitTestVisible = value;
                }
            }
    
            /// <summary>
            ///     The single child of an <see cref="System.Windows.Media.Animation.OverlayRenderDecorator" />
            /// </summary>
            [DefaultValue(null)]
            public virtual UIElement Child
            {
                get { return _child; }
                set
                {
                    if (_child != value)
                    {
                        //need to remove old element from logical tree
                        if (_child != null)
                        {
                            OnDetachChild(_child);
                            RemoveLogicalChild(_child);
                        }
    
                        _vc.Clear();
    
                        if (value != null)
                        {
                            //add to visual
                            _vc.Add(value);
                            //add to logical
                            AddLogicalChild(value);
                        }
    
                        //always add the overlay child back into the visual tree if its set
                        if (_overlayVisual != null)
                            _vc.Add(_overlayVisual);
    
                        //cache the new child
                        _child = value;
    
                        //notify derived types of the new child
                        if (value != null)
                            OnAttachChild(_child);
    
                        InvalidateMeasure();
                    }
                }
            }
    
            /// <summary>
            ///     Returns enumerator to logical children.
            /// </summary>
            protected override IEnumerator LogicalChildren
            {
                get
                {
                    if (_child == null)
                    {
                        return new List<UIElement>().GetEnumerator();
                    }
                    var l = new List<UIElement> {_child};
                    return l.GetEnumerator();
                }
            }
    
            #endregion
    
            //-------------------------------------------------------------------
            //
            //  Protected Methods
            //
            //-------------------------------------------------------------------
    
            #region Protected Methods
    
            /// <summary>
            ///     Updates DesiredSize of the OverlayRenderDecorator.  Called by parent UIElement.  This is the first pass of layout.
            /// </summary>
            /// <remarks>
            ///     OverlayRenderDecorator determines a desired size it needs from the child's sizing properties, margin, and requested
            ///     size.
            /// </remarks>
            /// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param>
            /// <returns>The OverlayRenderDecorator's desired size.</returns>
            protected override Size MeasureOverride(Size constraint)
            {
                var child = Child;
                if (child != null)
                {
                    child.Measure(constraint);
                    return (child.DesiredSize);
                }
                return (new Size());
            }
    
            /// <summary>
            ///     OverlayRenderDecorator computes the position of its single child inside child's Margin and calls Arrange
            ///     on the child.
            /// </summary>
            /// <param name="arrangeSize">Size the OverlayRenderDecorator will assume.</param>
            protected override Size ArrangeOverride(Size arrangeSize)
            {
                var child = Child;
                child?.Arrange(new Rect(arrangeSize));
    
                //Our OnRender gets called in Arrange, but
                //  we dont have access to that, so update the 
                //  overlay here.
                if (_overlayVisual != null)
                {
                    using (var dc = _overlayVisual.RenderOpen())
                    {
                        //delegate to derived types
                        OnOverlayRender(dc);
                    }
                }
    
                return (arrangeSize);
            }
    
            /// <summary>
            ///     render method for overlay graphics.
            /// </summary>
            /// <param name="dc"></param>
            protected virtual void OnOverlayRender(DrawingContext dc)
            {
            }
    
            /// <summary>
            ///     gives derives types a simple way to respond to a new child being added
            /// </summary>
            /// <param name="child"></param>
            protected virtual void OnAttachChild(UIElement child)
            {
            }
    
            /// <summary>
            ///     gives derives types a simple way to respond to a child being removed
            /// </summary>
            /// <param name="child"></param>
            protected virtual void OnDetachChild(UIElement child)
            {
            }
    
            protected override int VisualChildrenCount => _vc.Count;
    
            protected override Visual GetVisualChild(int index) => _vc[index];
    
            #endregion
        }

    FireworkEffect:

    //uielement
    //visual operations
    //animation effect stuff
    //LayoutOverrideDecorator
    
    public class FireworkEffect : OverlayRenderDecorator
    {
        private readonly Vector _gravity = new Vector(0.0, 10.0);
        private readonly List<Particle> _particles = new List<Particle>();
        private Point _lastMousePosition = new Point(0, 0);
        private double _secondsUntilDrop;
        private ParticleEffectsTimeTracker _timeTracker;
        protected Random Random = new Random();
    
        protected override void OnAttachChild(UIElement child)
        {
            CompositionTarget.Rendering += OnFrameCallback;
    
            child.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
            child.PreviewMouseMove += OnMouseMove;
    
            _timeTracker = new ParticleEffectsTimeTracker();
        }
    
        protected override void OnDetachChild(UIElement child)
        {
            CompositionTarget.Rendering -= OnFrameCallback;
    
            child.PreviewMouseLeftButtonUp -= OnMouseLeftButtonUp;
            child.PreviewMouseMove -= OnMouseMove;
    
            _timeTracker = null;
        }
    
        protected void OnFrameCallback(object sender, EventArgs e)
        {
            UpdateParticles(_timeTracker.Update());
        }
    
        protected virtual void UpdateParticles(double deltatime)
        {
            //drop particles from mouse position
            if (MouseDropsParticles && IsMouseOver)
            {
                _secondsUntilDrop -= deltatime;
                if (_secondsUntilDrop < 0.0)
                {
                    AddRandomBurst(_lastMousePosition - new Vector(Radius/2.0, Radius/2.0), 1);
                    _secondsUntilDrop = MouseDropDelay + (Random.NextDouble()*2.0 - 1.0)*MouseDropDelayVariation;
                }
            }
    
            if (_particles.Count > 0)
                InvalidateVisual();
    
            //update all particles
            for (var i = 0; i < _particles.Count;)
            {
                //_particles[i]
                var p = _particles[i];
    
                if (GravitateToMouse)
                {
                    p.Velocity += (_lastMousePosition - p.Location)*GravitateScale;
                }
                else
                {
                    p.Velocity += _gravity;
                }
                p.Location += p.Velocity*deltatime;
    
                if (BounceOffContainer)
                {
                    var radius = p.Diameter/2.0;
                    if (p.Location.X - radius < 0.0)
                    {
                        p.Location.X = radius;
                        p.Velocity.X *= -0.9;
                    }
                    else if (p.Location.X > ActualWidth - radius)
                    {
                        p.Location.X = ActualWidth - radius;
                        p.Velocity.X *= -0.9;
                    }
                    if (p.Location.Y - radius < 0.0)
                    {
                        p.Location.Y = radius;
                        p.Velocity.Y *= -0.9;
                    }
                    else if (p.Location.Y > ActualHeight - radius)
                    {
                        p.Location.Y = ActualHeight - radius;
                        p.Velocity.Y *= -0.9;
                    }
                }
    
                //only increment counter for live particles
                if (_timeTracker.ElapsedTime > p.DeathTime)
                    _particles.RemoveAt(i);
                else
                    i++;
            }
        }
    
        protected override void OnOverlayRender(DrawingContext drawingContext)
        {
            foreach (var p in _particles)
            {
                //figure out where in the particles life we are
                var particlelife = (_timeTracker.ElapsedTime - p.LifeTime).TotalSeconds/
                                   (p.DeathTime - p.LifeTime).TotalSeconds;
                var currentcolor = Color.Multiply(p.StartColor, (float) (1.0 - particlelife)) +
                                   Color.Multiply(p.EndColor, (float) particlelife);
                Brush brush = new RadialGradientBrush(currentcolor,
                    Color.FromArgb(0, currentcolor.R, currentcolor.G, currentcolor.B));
    
                var rect =
                    new RectangleGeometry(
                        new Rect(new Point(p.Location.X - p.Diameter/2.0, p.Location.Y - p.Diameter/2.0),
                            new Size(p.Diameter, p.Diameter)));
                drawingContext.DrawGeometry(brush, null, rect);
            }
        }
    
        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            _lastMousePosition = e.GetPosition(this);
        }
    
        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            AddRandomBurst(e.GetPosition(this));
        }
    
        public void AddRandomBurst()
        {
            var point = new Point(Random.NextDouble()*ActualWidth, Random.NextDouble()*ActualHeight);
            AddRandomBurst(point, ClickBurstSize);
        }
    
        public void AddRandomBurst(Point location)
        {
            AddRandomBurst(location, ClickBurstSize);
        }
    
        public void AddRandomBurst(Point location, int count)
        {
            for (var i = 0; i < count; i++)
            {
                var p = new Particle();
    
                var radius = Radius + (Random.NextDouble()*2.0 - 1.0)*RadiusVariation;
                var lifetime = Random.NextDouble()*3.0 + 1.0;
    
                p.Location = location;
                p.Velocity = new Vector(Random.NextDouble()*200.0 - 100.0, Random.NextDouble()*-200 + 100.0);
                p.LifeTime = _timeTracker.ElapsedTime;
                p.DeathTime = _timeTracker.ElapsedTime + TimeSpan.FromSeconds(lifetime);
                p.Diameter = 2.0*radius;
    
                var startColor = StartColor;
                var startColorVariation = StartColorVariation;
                var endColor = EndColor;
                var endColorVariation = EndColorVariation;
    
                var startRandColor = Color.FromScRgb(startColorVariation.ScA*(float) (Random.NextDouble()*2.0 - 1.0),
                    startColorVariation.ScR*(float) (Random.NextDouble()*2.0 - 1.0),
                    startColorVariation.ScG*(float) (Random.NextDouble()*2.0 - 1.0),
                    startColorVariation.ScB*(float) (Random.NextDouble()*2.0 - 1.0));
                var endRandColor = Color.FromScRgb(endColorVariation.ScA*(float) (Random.NextDouble()*2.0 - 1.0),
                    endColorVariation.ScR*(float) (Random.NextDouble()*2.0 - 1.0),
                    endColorVariation.ScG*(float) (Random.NextDouble()*2.0 - 1.0),
                    endColorVariation.ScB*(float) (Random.NextDouble()*2.0 - 1.0));
    
                p.StartColor = startColor + startRandColor;
                p.EndColor = endColor + endRandColor;
                _particles.Add(p);
            }
        }
    
        #region Dependency Properties
    
        public static readonly DependencyProperty RadiusProperty =
            DependencyProperty.Register(
                "RadiusBase",
                typeof (double),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(15.0)
                );
    
        public static readonly DependencyProperty RadiusVariationProperty =
            DependencyProperty.Register(
                "RadiusVariation",
                typeof (double),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(5.0)
                );
    
        public static readonly DependencyProperty StartColorProperty =
            DependencyProperty.Register(
                "StartColor",
                typeof (Color),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(Color.FromArgb(245, 200, 50, 20))
                );
    
        public static readonly DependencyProperty EndColorProperty =
            DependencyProperty.Register(
                "EndColor",
                typeof (Color),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(Color.FromArgb(100, 200, 255, 20))
                );
    
        public static readonly DependencyProperty StartColorVariationProperty =
            DependencyProperty.Register(
                "StartColorVariation",
                typeof (Color),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(Color.FromArgb(10, 55, 50, 20))
                );
    
        public static readonly DependencyProperty EndColorVariationProperty =
            DependencyProperty.Register(
                "EndColorVariation",
                typeof (Color),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(Color.FromArgb(50, 20, 100, 20))
                );
    
        public static readonly DependencyProperty MouseDropDelayProperty =
            DependencyProperty.Register(
                "MouseDropDelay",
                typeof (double),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(0.1)
                );
    
        public static readonly DependencyProperty MouseDropDelayVariationProperty =
            DependencyProperty.Register(
                "MouseDropDelayVariation",
                typeof (double),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(0.05)
                );
    
        public static readonly DependencyProperty ClickBurstSizeProperty =
            DependencyProperty.Register(
                "ClickBurstSize",
                typeof (int),
                typeof (FireworkEffect),
                new FrameworkPropertyMetadata(30)
                );
    
        #endregion
    
        #region Properties
    
        public double Radius
        {
            get { return (double) GetValue(RadiusProperty); }
            set { SetValue(RadiusProperty, value); }
        }
    
        public double RadiusVariation
        {
            get { return (double) GetValue(RadiusVariationProperty); }
            set { SetValue(RadiusVariationProperty, value); }
        }
    
        public Color StartColor
        {
            get { return (Color) GetValue(StartColorProperty); }
            set { SetValue(StartColorProperty, value); }
        }
    
        public Color EndColor
        {
            get { return (Color) GetValue(EndColorProperty); }
            set { SetValue(EndColorProperty, value); }
        }
    
        public Color StartColorVariation
        {
            get { return (Color) GetValue(StartColorVariationProperty); }
            set { SetValue(StartColorVariationProperty, value); }
        }
    
        public Color EndColorVariation
        {
            get { return (Color) GetValue(EndColorVariationProperty); }
            set { SetValue(EndColorVariationProperty, value); }
        }
    
    
        public bool BounceOffContainer { get; set; } = false;
    
        public bool GravitateToMouse { get; set; } = false;
    
        public double GravitateScale { get; set; } = 0.1;
    
        public bool MouseDropsParticles { get; set; } = false;
    
        public double MouseDropDelay
        {
            get { return (double) GetValue(MouseDropDelayProperty); }
            set { SetValue(MouseDropDelayProperty, value); }
        }
    
        public double MouseDropDelayVariation
        {
            get { return (double) GetValue(MouseDropDelayVariationProperty); }
            set { SetValue(MouseDropDelayVariationProperty, value); }
        }
    
        public int ClickBurstSize
        {
            get { return (int) GetValue(ClickBurstSizeProperty); }
            set { SetValue(ClickBurstSizeProperty, value); }
        }
    
        #endregion
    }

    SonicEffect:

    //uielement
    //visual operations
    
    public class SonicEffect : OverlayRenderDecorator
    {
        protected override void OnAttachChild(UIElement child)
        {
            child.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
        }
    
        protected override void OnDetachChild(UIElement child)
        {
            CompositionTarget.Rendering -= OnFrameCallback;
    
            child.PreviewMouseLeftButtonUp -= OnMouseLeftButtonUp;
            _timeTracker = null;
        }
    
        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_timeTracker != null)
            {
                _timeTracker.TimerFired -= OnTimerFired;
                _timeTracker = null;
            }
    
            CompositionTarget.Rendering += OnFrameCallback;
            _timeTracker = new ParticleEffectsTimeTracker {TimerInterval = _ringDelayInSeconds};
            _timeTracker.TimerFired += OnTimerFired;
            _lowerRing = _upperRing = 0;
            _clickPosition = e.GetPosition(this);
        }
    
        private void OnFrameCallback(object sender, EventArgs e)
        {
            if (_timeTracker != null)
            {
                _timeTracker.Update();
                InvalidateVisual();
            }
        }
    
        private void OnTimerFired(object sender, EventArgs e)
        {
            if (_upperRing < RingCount)
            {
                _upperRing++;
            }
            else
            {
                _lowerRing++;
                if (_lowerRing >= _upperRing)
                {
                    _timeTracker.TimerFired -= OnTimerFired;
                    _timeTracker = null;
                    CompositionTarget.Rendering -= OnFrameCallback;
                }
            }
        }
    
        protected override void OnOverlayRender(DrawingContext dc)
        {
            if (_timeTracker != null)
            {
                for (var i = _lowerRing; i < _upperRing; i++)
                {
                    var radius = RingRadius*(i + 1);
                    dc.DrawEllipse(Brushes.Transparent, new Pen(new SolidColorBrush(RingColor), RingThickness),
                        _clickPosition, radius, radius);
                }
            }
        }
    
        #region Private Members
    
        private ParticleEffectsTimeTracker _timeTracker;
        private double _ringDelayInSeconds = 3;
        private Point _clickPosition;
        private int _lowerRing, _upperRing;
    
        #endregion
    
        #region Properties
    
        public int RingCount { get; set; } = 5;
    
        public TimeSpan RingDelay
        {
            get { return TimeSpan.FromSeconds(_ringDelayInSeconds); }
            set { _ringDelayInSeconds = value.TotalSeconds; }
        }
    
        public double RingRadius { get; set; } = 7.0;
    
        public double RingThickness { get; set; } = 5.0;
    
        public Color RingColor { get; set; } = Color.FromArgb(128, 128, 128, 128);
    
        #endregion
    }

    MagnitismCanvas:

    public class MagnitismCanvas : Canvas
    {
        public MagnitismCanvas()
        {
            // suppress movement in the visual studio designer.
            if (Process.GetCurrentProcess().ProcessName != "devenv")
                CompositionTarget.Rendering += UpdateChildren;
            _timeTracker = new ParticleEffectsTimeTracker();
        }
    
        private void UpdateChildren(object sender, EventArgs e)
        {
            //update time delta
            _timeTracker.Update();
    
            foreach (UIElement child in LogicalTreeHelper.GetChildren(this))
            {
                var velocity = _childrenVelocities.ContainsKey(child) ? _childrenVelocities[child] : new Vector(0, 0);
    
                //compute velocity dampening
                velocity = velocity*Drag;
    
                var truePosition = GetTruePosition(child);
                var childRect = new Rect(truePosition, child.RenderSize);
    
    
                //accumulate forces
                var forces = new Vector(0, 0);
    
                //add wall repulsion
                forces.X += BorderForce/Math.Max(1, childRect.Left);
                forces.X -= BorderForce/Math.Max(1, RenderSize.Width - childRect.Right);
                forces.Y += BorderForce/Math.Max(1, childRect.Top);
                forces.Y -= BorderForce/Math.Max(1, RenderSize.Height - childRect.Bottom);
    
                //each other child pushes away based on the square distance
                foreach (UIElement otherchild in LogicalTreeHelper.GetChildren(this))
                {
                    //dont push against itself
                    if (otherchild == child)
                        continue;
    
                    var otherchildtruePosition = GetTruePosition(otherchild);
                    var otherchildRect = new Rect(otherchildtruePosition, otherchild.RenderSize);
    
                    //make sure rects aren't the same
                    if (otherchildRect == childRect)
                        continue;
    
                    //ignore children with a size of 0,0
                    if (otherchildRect.Width == 0 && otherchildRect.Height == 0 ||
                        childRect.Width == 0 && childRect.Height == 0)
                        continue;
    
                    //vector from current other child to current child
                    //are they overlapping?  if so, distance is 0
                    var toChild = AreRectsOverlapping(childRect, otherchildRect)
                        ? new Vector(0, 0)
                        : VectorBetweenRects(childRect, otherchildRect);
    
                    var length = toChild.Length;
                    if (length < 1)
                    {
                        length = 1;
                        var childCenter = GetCenter(childRect);
                        var otherchildCenter = GetCenter(otherchildRect);
                        //compute toChild from the center of both rects
                        toChild = childCenter - otherchildCenter;
                    }
    
                    var childpush = ChildForce/length;
    
                    toChild.Normalize();
                    forces += toChild*childpush;
                }
    
                //add forces to velocity and store it for next iteration
                velocity += forces;
                _childrenVelocities[child] = velocity;
    
                //move the object based on it's velocity
                SetTruePosition(child, truePosition + _timeTracker.DeltaSeconds*velocity);
            }
        }
    
        private bool AreRectsOverlapping(Rect r1, Rect r2)
        {
            if (r1.Bottom < r2.Top) return false;
            if (r1.Top > r2.Bottom) return false;
    
            if (r1.Right < r2.Left) return false;
            if (r1.Left > r2.Right) return false;
    
            return true;
        }
    
        private Point IntersectInsideRect(Rect r, Point raystart, Vector raydir)
        {
            var xtop = raystart.X + raydir.X*(r.Top - raystart.Y)/raydir.Y;
            var xbottom = raystart.X + raydir.X*(r.Bottom - raystart.Y)/raydir.Y;
            var yleft = raystart.Y + raydir.Y*(r.Left - raystart.X)/raydir.X;
            var yright = raystart.Y + raydir.Y*(r.Right - raystart.X)/raydir.X;
            var top = new Point(xtop, r.Top);
            var bottom = new Point(xbottom, r.Bottom);
            var left = new Point(r.Left, yleft);
            var right = new Point(r.Right, yright);
            var tv = raystart - top;
            var bv = raystart - bottom;
            var lv = raystart - left;
            var rv = raystart - right;
            //classify ray direction
            if (raydir.Y < 0)
            {
                if (raydir.X < 0) //top left
                {
                    if (tv.LengthSquared < lv.LengthSquared)
                        return top;
                    return left;
                }
                if (tv.LengthSquared < rv.LengthSquared)
                    return top;
                return right;
            }
            if (raydir.X < 0) //bottom left
            {
                if (bv.LengthSquared < lv.LengthSquared)
                    return bottom;
                return left;
            }
            if (bv.LengthSquared < rv.LengthSquared)
                return bottom;
            return right;
        }
    
        private Vector VectorBetweenRects(Rect r1, Rect r2)
        {
            //find the edge points and use these to measure the distance
            var r1Center = GetCenter(r1);
            var r2Center = GetCenter(r2);
            var between = (r1Center - r2Center);
            between.Normalize();
            var edge1 = IntersectInsideRect(r1, r1Center, -between);
            var edge2 = IntersectInsideRect(r2, r2Center, between);
            return edge1 - edge2;
        }
    
        private Point GetRenderTransformOffset(UIElement e)
        {
            //make sure they object's render transform is a translation
            var renderTranslation = e.RenderTransform as TranslateTransform;
            if (renderTranslation == null)
            {
                renderTranslation = new TranslateTransform(0, 0);
                e.RenderTransform = renderTranslation;
            }
    
            return new Point(renderTranslation.X, renderTranslation.Y);
        }
    
        private void SetRenderTransformOffset(UIElement e, Point offset)
        {
            //make sure they object's render transform is a translation
            var renderTranslation = e.RenderTransform as TranslateTransform;
            if (renderTranslation == null)
            {
                renderTranslation = new TranslateTransform(0, 0);
                e.RenderTransform = renderTranslation;
            }
    
            //set new offset
            renderTranslation.X = offset.X;
            renderTranslation.Y = offset.Y;
        }
    
        private Point GetTruePosition(UIElement e)
        {
            var renderTranslation = GetRenderTransformOffset(e);
            return new Point(GetLeft(e) + renderTranslation.X, GetTop(e) + renderTranslation.Y);
        }
    
        private void SetTruePosition(UIElement e, Point p)
        {
            var canvasOffset = new Vector(GetLeft(e), GetTop(e));
            var renderTranslation = p - canvasOffset;
    
            SetRenderTransformOffset(e, renderTranslation);
        }
    
        private Point GetCenter(Rect r) => new Point((r.Left + r.Right) / 2.0, (r.Top + r.Bottom) / 2.0);
    
        #region Private Members
    
        private readonly ParticleEffectsTimeTracker _timeTracker;
        private readonly Dictionary<UIElement, Vector> _childrenVelocities = new Dictionary<UIElement, Vector>();
    
        #endregion
    
        #region Properties
    
        public double BorderForce { get; set; } = 1000.0;
    
        public double ChildForce { get; set; } = 200.0;
    
        public double Drag { get; set; } = 0.9;
    
        #endregion
    }

    ParticleEffectsTimeTracker:

    //uielement
    //visual operations
    
    //animation effect stuff
    
    public class ParticleEffectsTimeTracker
    {
        #region Constructors
    
        public ParticleEffectsTimeTracker()
        {
            ElapsedTime = DateTime.Now;
        }
    
        #endregion
    
        #region Events
    
        public event EventHandler TimerFired;
    
        #endregion
    
        public double Update()
        {
            var currentTime = DateTime.Now;
    
    
            //get the difference in time
            var diffTime = currentTime - ElapsedTime;
            DeltaSeconds = diffTime.TotalSeconds;
    
    
            //does the user want a callback on regular intervals?
            if (TimerInterval > 0.0)
            {
                /*
                    //compute the intervals for this and previous update
                    int currInterval = (int)(currentTime / TimeSpan.FromSeconds(_timerInterval));
                    int prevInterval = (int)(_lastTime / TimeSpan.FromSeconds(_timerInterval));
    
                    //has the interval changed since last update?
                    if (currInterval != prevInterval)
                    {
                        //fire interval event
                        //note that this will only be called once per frame at most
                        // so if they interval is too small, you wont get 2+ fires per frame
                        TimerFired(this, null);
                    } */
    
                if (currentTime != ElapsedTime)
                {
                    TimerFired?.Invoke(this, null);
                }
            }
    
    
            //cycle old time
            ElapsedTime = currentTime;
    
            return DeltaSeconds;
        }
    
        #region Private Memebers
    
        #endregion
    
        #region Properties
    
        public double TimerInterval { get; set; } = -1;
    
        public DateTime ElapsedTime { get; private set; }
    
        public double DeltaSeconds { get; private set; }
    
        #endregion
    }

    Particle:

    internal class Particle
    {
        public DateTime DeathTime;
        public double Diameter;
        public Color EndColor;
        public DateTime LifeTime;
        public Point Location;
        public Color StartColor;
        public Vector Velocity;
    }

    代码解析:

    1. OverlayRenderDecoratorOverlayVisual属性IsHitTestVisible 为什么设置为False?

      1. 当为True时,点击一次出现微粒爆发,此时再点击时会执行微粒上的点击命中并阻止进行下一层visual命中测试,因此按钮不会触发点击事件。
      2. 当为false时,微粒visual层不触发命中测试,直接进行下一层按钮的命中测试,因此会执行按钮点击事件,并会再次爆发出微粒。

    3.此属性受继承类的IsOverlayHitTestVisible属性关联开关管理。

    后续补充详细---

    展开全文
  • 实现效果:1、X轴上各种缓动动画效果2、自定义动画代码实现文件组织: 一、界面代码 界面容器为Grid方格下使用Canvas,Canvas承载TextBlock和Button 动画开始的操作有两种方式,一种为点击Go按钮执行所有动画,一种...
        

    CustomAnimation自定义动画

    clipboard.png

    实现效果:
    1、X轴上各种缓动动画效果
    2、自定义动画代码实现
    文件组织:

    clipboard.png

    一、界面代码

    1. 界面容器为Grid方格下使用Canvas,Canvas承载TextBlock和Button
    2. 动画开始的操作有两种方式,一种为点击Go按钮执行所有动画,一种为单独单击按钮会执行相应按钮动画+第一个Linear按钮动画。
    3. 演示板作为静态资源共享,统一在页面加载触发器,触发条件为上面的2种操作方式。

    主要BounceEase、ElasticEase、circle按钮布置代码:

    <Canvas Grid.Row="2">
        <TextBlock Canvas.Left="85" Canvas.Top="-16" FontSize="108" Foreground="LightGray">Bounce!</TextBlock>
        <Button Name="easeInButtonBounce" Canvas.Top="10">
          <Button.RenderTransform>
            <TranslateTransform X="0" Y="0"/>
          </Button.RenderTransform>
            Beginning!
        </Button>
        <Button Name="easeOutButtonBounce" Canvas.Top="40">
          <Button.RenderTransform>
            <TranslateTransform X="0" Y="0"/>
          </Button.RenderTransform>
            End!
        </Button>
        <Button Name="easeInOutButtonBounce" Canvas.Top="70">
          <Button.RenderTransform>
            <TranslateTransform X="0" Y="0"/>
          </Button.RenderTransform>
            Both!
        </Button>
    </Canvas>

    主要演示板资源代码:
    弹跳BounceDoubleAnimation注册属性有:EdgeBehavior

    <Storyboard x:Key="BounceEaseInTimeline">
      <customAnimations:BounceDoubleAnimation 
          From="0" To="500" Duration="0:0:5" EdgeBehavior="EaseIn" Storyboard.TargetName="easeInButtonBounce" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
    </Storyboard>
    
    <Storyboard x:Key="BounceEaseOutTimeline">
      <customAnimations:BounceDoubleAnimation From="0" To="500" Duration="0:0:5" EdgeBehavior="EaseOut" Storyboard.TargetName="easeOutButtonBounce" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
    </Storyboard>
    
    <Storyboard x:Key="BounceEaseInOutTimeline">
      <customAnimations:BounceDoubleAnimation From="0" To="500" Duration="0:0:5" EdgeBehavior="EaseInOut" Storyboard.TargetName="easeInOutButtonBounce" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
    </Storyboard>

    弹簧动画:ElasticDoubleAnimation

    <Storyboard x:Key="ElasticEaseInOutTimeline">
      <customAnimations:ElasticDoubleAnimation From="0" To="500" Duration="0:0:5" EdgeBehavior="EaseInOut" Storyboard.TargetName="easeInOutButtonElastic" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
    </Storyboard>

    圆圈BounceEase动画:
    ps:其中注释部分是可以省掉而不影响实现效果。

    1. Circle1动画为沿X轴绕圈运动
    2. Circle2d动画为在X轴上一点原地绕圈运动,然后平移到终点,注意动画X值点与时间线配合。
    <Storyboard x:Key="CircleTimeline">
      <DoubleAnimation Duration="0:0:5" From="0" To="500" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
      <!--<DoubleAnimation Duration="0:0:1.5" From="0" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>-->
      <ParallelTimeline BeginTime="0:0:0" Duration="0:0:4.5">
        <customAnimations:CircleAnimation RepeatBehavior="Forever" Duration="0:0:1" Radius="40" Direction="YDirection" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>
        <customAnimations:CircleAnimation RepeatBehavior="Forever" Duration="0:0:1" Radius="40" Direction="XDirection" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
      </ParallelTimeline>
      <!--<ParallelTimeline BeginTime="0:0:4.5">
        <DoubleAnimation To="500" Duration="0:0:0.5" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
        <DoubleAnimation To="0.0" Duration="0:0:0.5" Storyboard.TargetName="circleButton" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>
      </ParallelTimeline>-->
    
    </Storyboard>
    
    <Storyboard x:Key="CircleTimeline2">
      <DoubleAnimation Duration="0:0:1.5" From="0" To="290" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
      <!--<DoubleAnimation Duration="0:0:1.5" From="0" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>-->
      <ParallelTimeline BeginTime="0:0:1.5" Duration="0:0:2">
        <customAnimations:CircleAnimation RepeatBehavior="Forever" Duration="0:0:0.25" Radius="40" Direction="YDirection" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>
        <customAnimations:CircleAnimation RepeatBehavior="Forever" Duration="0:0:0.25" Radius="40" Direction="XDirection" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
      </ParallelTimeline>
      <ParallelTimeline BeginTime="0:0:3.5">
        <DoubleAnimation To="500" Duration="0:0:1.5" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"/>
        <!--<DoubleAnimation To="0.0" Duration="0:0:0.5" Storyboard.TargetName="circleButton2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"/>-->
      </ParallelTimeline>
    </Storyboard>
    
      </Window.Resources>

    统一触发代码:

    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="goButton">
          <BeginStoryboard Storyboard="{StaticResource LinearTimeline}"/>
            <BeginStoryboard Storyboard="{StaticResource AccelTimeline}"/>
            <BeginStoryboard Storyboard="{StaticResource DecelTimeline}"/>
            <BeginStoryboard Storyboard="{StaticResource AccelDecelTimeline}"/>
            <BeginStoryboard Storyboard="{StaticResource BounceEaseInTimeline}"/>
            
    <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="linearButton">
        <BeginStoryboard Storyboard="{StaticResource LinearTimeline}"/>
    </EventTrigger>

    后台代码:
    本实例自定义实现缓动函数EasingFunctionBase的一部分具体子效果,在xaml示例中还可以设置各项缓动效果的属性参数,详细见第2章。
    BounceAnimation弹球动画自定义:

    1. Bounce自定义弹球算法:此处不详述,只知道有个大概方法,获取特定公式函数值,然后根据EaseMode来增减量返回
    2. .Net中BounceEase与此原理相识,都可以设置Bounces、Bounciness参数
    protected override double GetCurrentValueCore(
        double defaultOriginValue,
        double defaultDestinationValue,
        AnimationClock clock)
    {
        double returnValue;
        var start = From ?? defaultOriginValue;
        var delta = To - start ?? defaultOriginValue - start;
    
        switch (EdgeBehavior)
        {
            case EdgeBehaviorEnum.EaseIn:
                returnValue = EaseIn(clock.CurrentProgress.Value, start, delta, Bounciness, Bounces);
                break;
            case EdgeBehaviorEnum.EaseOut:
                returnValue = EaseOut(clock.CurrentProgress.Value, start, delta, Bounciness, Bounces);
                break;
            default:
                returnValue = EaseInOut(clock.CurrentProgress.Value, start, delta, Bounciness, Bounces);
                break;
        }
        return returnValue;
    }
    
    protected override Freezable CreateInstanceCore() => new BounceDoubleAnimation();
    
    private static double EaseOut(double timeFraction, double start, double delta, double bounciness, int bounces)
    {
        // math magic: The cosine gives us the right wave, the timeFraction is the frequency of the wave, 
        // the absolute value keeps every value positive (so it "bounces" off the midpoint of the cosine 
        // wave, and the amplitude (the exponent) makes the sine wave get smaller and smaller at the end.
        var returnValue = Math.Abs(Math.Pow((1 - timeFraction), bounciness)
                                   *Math.Cos(2*Math.PI*timeFraction*bounces));
        returnValue = delta - (returnValue*delta);
        returnValue += start;
        return returnValue;
    }
    
    private static double EaseIn(double timeFraction, double start, double delta, double bounciness, int bounces)
    {
        // math magic: The cosine gives us the right wave, the timeFraction is the amplitude of the wave, 
        // the absolute value keeps every value positive (so it "bounces" off the midpoint of the cosine 
        // wave, and the amplitude (the exponent) makes the sine wave get bigger and bigger towards the end.
        var returnValue = Math.Abs(Math.Pow((timeFraction), bounciness)
                                   *Math.Cos(2*Math.PI*timeFraction*bounces));
        returnValue = returnValue*delta;
        returnValue += start;
        return returnValue;
    }
    
    private static double EaseInOut(double timeFraction, double start, double delta, double bounciness, int bounces)
    {
        double returnValue;
    
        // we cut each effect in half by multiplying the time fraction by two and halving the distance.
        if (timeFraction <= 0.5)
        {
            returnValue = EaseIn(timeFraction*2, start, delta/2, bounciness, bounces);
        }
        else
        {
            returnValue = EaseOut((timeFraction - 0.5)*2, start, delta/2, bounciness, bounces);
            returnValue += delta/2;
        }
        return returnValue;
    }

    ElasticDoubleAnimation弹簧动画自定义

    1. 弹簧动画,结构方式与上面类似,其属性参与类似ElasticEaseh缓动函数
    2. 算法如下:
    protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue,
        AnimationClock clock)
    {
        double returnValue;
        var start = From ?? defaultOriginValue;
        var delta = To - start ?? defaultOriginValue - start;
        switch (EdgeBehavior)
        {
            case EdgeBehaviorEnum.EaseIn:
                returnValue = EaseIn(clock.CurrentProgress.Value, start, delta, Springiness, Oscillations);
                break;
            case EdgeBehaviorEnum.EaseOut:
                returnValue = EaseOut(clock.CurrentProgress.Value, start, delta, Springiness, Oscillations);
                break;
            default:
                returnValue = EaseInOut(clock.CurrentProgress.Value, start, delta, Springiness, Oscillations);
                break;
        }
        return returnValue;
    }
    
    protected override Freezable CreateInstanceCore() => new ElasticDoubleAnimation();
    
    private static double EaseOut(double timeFraction, double start, double delta, double springiness,
        double oscillations)
    {
        // math magic: The cosine gives us the right wave, the timeFraction * the # of oscillations is the 
        // frequency of the wave, and the amplitude (the exponent) makes the wave get smaller at the end
        // by the "springiness" factor. This is extremely similar to the bounce equation.
        var returnValue = Math.Pow((1 - timeFraction), springiness)
                          *Math.Cos(2*Math.PI*timeFraction*oscillations);
        returnValue = delta - (returnValue*delta);
        returnValue += start;
        return returnValue;
    }
    
    private static double EaseIn(double timeFraction, double start, double delta, double springiness,
        double oscillations)
    {
        // math magic: The cosine gives us the right wave, the timeFraction * the # of oscillations is the 
        // frequency of the wave, and the amplitude (the exponent) makes the wave get smaller at the beginning
        // by the "springiness" factor. This is extremely similar to the bounce equation. 
        var returnValue = Math.Pow((timeFraction), springiness)
                          *Math.Cos(2*Math.PI*timeFraction*oscillations);
        returnValue = returnValue*delta;
        returnValue += start;
        return returnValue;
    }
    
    private static double EaseInOut(double timeFraction, double start, double delta, double springiness,
        double oscillations)
    {
        double returnValue;
    
        // we cut each effect in half by multiplying the time fraction by two and halving the distance.
        if (timeFraction <= 0.5)
        {
            return EaseIn(timeFraction*2, start, delta/2, springiness, oscillations);
        }
        returnValue = EaseOut((timeFraction - 0.5)*2, start, delta/2, springiness, oscillations);
        returnValue += (delta/2);
        return returnValue;
    }
    }

    CircleAnimation圆圈动画自定义:

    1. 与.NET的CircleEase完全不同,后者无设置参数,而前者有X、Y方向、半径大小属性参数。
    2. 另外是原地圆圈运动,所有不像上述自定义属性From/To等
    3. 同时确定X、Y轴方向动画形成了原地圆圈动画,且看其简约的代码:
    /// <summary>
    ///     CircleAnimation: calculates polar coordinates as a function of time.
    ///     Use two of these (XDirection and YDirection) to move an element in an elliptical manner
    /// </summary>
    public class CircleAnimation : DoubleAnimationBase
    {
        public enum DirectionEnum
        {
            XDirection,
            YDirection
        }
    
        public static readonly DependencyProperty DirectionProperty =
            DependencyProperty.Register("Direction", typeof (DirectionEnum), typeof (CircleAnimation),
                new PropertyMetadata(DirectionEnum.XDirection));
    
        public static readonly DependencyProperty RadiusProperty =
            DependencyProperty.Register("Radius", typeof (double), typeof (CircleAnimation),
                new PropertyMetadata((double) 10));
    
        /// <summary>
        ///     distance from origin to polar coordinate
        /// </summary>
        public double Radius
        {
            get { return (double) GetValue(RadiusProperty); }
            set
            {
                if (value > 0.0)
                {
                    SetValue(RadiusProperty, value);
                }
                else
                {
                    throw new ArgumentException("a radius of " + value + " is not allowed!");
                }
            }
        }
    
        /// <summary>
        ///     are we measuring in the X or Y direction?
        /// </summary>
        public DirectionEnum Direction
        {
            get { return (DirectionEnum) GetValue(DirectionProperty); }
            set { SetValue(DirectionProperty, value); }
        }
    
        protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue,
            AnimationClock clock)
        {
            var time = clock.CurrentProgress.Value;
    
            // math magic: calculate new coordinates using polar coordinate equations. This requires two 
            // animations to be wired up in order to move in a circle, since we don't make any assumptions
            // about what we're animating (e.g. a TranslateTransform). 
            var returnValue = Direction == DirectionEnum.XDirection
                ? Math.Cos(2*Math.PI*time)
                : Math.Sin(2*Math.PI*time);
    
            // Need to add the defaultOriginValue so that composition works.
            return returnValue*Radius + defaultOriginValue;
        }
    
        protected override Freezable CreateInstanceCore() => new CircleAnimation();
    }

    BackDoubleAnimation后退下动画效果

    1. 同理BackDoubleAnimation自定义动画与BackEase参数不一样,前者只有Amplitude/Suppression,h后者只有Amplitudesh属性。
    2. 完整代码如下:
    /// <summary>
    ///     BackDoubleAnimation: goes in the opposite direction first
    /// </summary>
    public class BackDoubleAnimation : DoubleAnimationBase
    {
        public enum EdgeBehaviorEnum
        {
            EaseIn,
            EaseOut,
            EaseInOut
        }
    
        public static readonly DependencyProperty EdgeBehaviorProperty =
            DependencyProperty.Register("EdgeBehavior", typeof (EdgeBehaviorEnum), typeof (BackDoubleAnimation),
                new PropertyMetadata(EdgeBehaviorEnum.EaseIn));
    
        public static readonly DependencyProperty AmplitudeProperty =
            DependencyProperty.Register("Amplitude", typeof (double), typeof (BackDoubleAnimation),
                new PropertyMetadata(4.0));
    
        public static readonly DependencyProperty SuppressionProperty =
            DependencyProperty.Register("Suppression", typeof (double), typeof (BackDoubleAnimation),
                new PropertyMetadata(2.0));
    
        public static readonly DependencyProperty FromProperty =
            DependencyProperty.Register("From",
                typeof (double?),
                typeof (BackDoubleAnimation),
                new PropertyMetadata(null));
    
        public static readonly DependencyProperty ToProperty =
            DependencyProperty.Register("To",
                typeof (double?),
                typeof (BackDoubleAnimation),
                new PropertyMetadata(null));
    
        /// <summary>
        ///     which side gets the effect
        /// </summary>
        public EdgeBehaviorEnum EdgeBehavior
        {
            get { return (EdgeBehaviorEnum) GetValue(EdgeBehaviorProperty); }
            set { SetValue(EdgeBehaviorProperty, value); }
        }
    
        /// <summary>
        ///     how much backwards motion is there in the effect
        /// </summary>
        public double Amplitude
        {
            get { return (double) GetValue(AmplitudeProperty); }
            set { SetValue(AmplitudeProperty, value); }
        }
    
        /// <summary>
        ///     how quickly the effect drops off vs. the entire timeline
        /// </summary>
        public double Suppression
        {
            get { return (double) GetValue(SuppressionProperty); }
            set { SetValue(SuppressionProperty, value); }
        }
    
        /// <summary>
        ///     Specifies the starting value of the animation.
        /// </summary>
        public double? From
        {
            get { return (double?) GetValue(FromProperty); }
            set { SetValue(FromProperty, value); }
        }
    
        /// <summary>
        ///     Specifies the ending value of the animation.
        /// </summary>
        public double? To
        {
            get { return (double?) GetValue(ToProperty); }
            set { SetValue(ToProperty, value); }
        }
    
        protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue,
            AnimationClock clock)
        {
            double returnValue;
            var start = From ?? defaultOriginValue;
            var delta = To - start ?? defaultOriginValue - start;
            switch (EdgeBehavior)
            {
                case EdgeBehaviorEnum.EaseIn:
                    returnValue = EaseIn(clock.CurrentProgress.Value, start, delta, Amplitude, Suppression);
                    break;
                case EdgeBehaviorEnum.EaseOut:
                    returnValue = EaseOut(clock.CurrentProgress.Value, start, delta, Amplitude, Suppression);
                    break;
                default:
                    returnValue = EaseInOut(clock.CurrentProgress.Value, start, delta, Amplitude, Suppression);
                    break;
            }
            return returnValue;
        }
    
        protected override Freezable CreateInstanceCore() => new BackDoubleAnimation();
    
        private static double EaseOut(double timeFraction, double start, double delta, double amplitude,
            double suppression)
        {
            var frequency = 0.5;
    
            // math magic: The sine gives us the right wave, the timeFraction * 0.5 (frequency) gives us only half 
            // of the full wave, the amplitude gives us the relative height of the peak, and the exponent makes the 
            // effect drop off more quickly by the "suppression" factor. 
            var returnValue = Math.Pow((timeFraction), suppression)
                              *amplitude*Math.Sin(2*Math.PI*timeFraction*frequency) + timeFraction;
            returnValue = (returnValue*delta);
            returnValue += start;
            return returnValue;
        }
    
        private static double EaseIn(double timeFraction, double start, double delta, double amplitude,
            double suppression)
        {
            var frequency = 0.5;
    
            // math magic: The sine gives us the right wave, the timeFraction * 0.5 (frequency) gives us only half 
            // of the full wave (flipped by multiplying by -1 so that we go "backwards" first), the amplitude gives 
            // us the relative height of the peak, and the exponent makes the effect start later by the "suppression" 
            // factor. 
            var returnValue = Math.Pow((1 - timeFraction), suppression)
                              *amplitude*Math.Sin(2*Math.PI*timeFraction*frequency)*-1 + timeFraction;
            returnValue = (returnValue*delta);
            returnValue += start;
            return returnValue;
        }
    
        private static double EaseInOut(double timeFraction, double start, double delta, double amplitude,
            double suppression)
        {
            double returnValue;
    
            // we cut each effect in half by multiplying the time fraction by two and halving the distance.
            if (timeFraction <= 0.5)
            {
                return EaseIn(timeFraction*2, start, delta/2, amplitude, suppression);
            }
            returnValue = EaseOut((timeFraction - 0.5)*2, start, delta/2, amplitude, suppression);
            returnValue += (delta/2);
            return returnValue;
        }
    }
    展开全文
  • InterpolationMethodsExample插补方式的帧动画 ...以下在StackPanel的附加属性按钮点击Button.Click中设置触发开始事件动画,并设置BeginStoryboard的Name,并由其他对应按钮进行控制** <StackPanel.T...
  • Wpf 抽屉效果

    2018-09-26 00:02:00
    原文:Wpf 抽屉效果在android开发中有抽屉效果,就是在页面的边上有一个按钮,可以通过点击或者拖拽这个按钮,让页面显示。Wpf也可以实现相同的效果。 主要是通过一个DoubleAnimation和RectAnimation动画实现 ...
  • wpf 控件多层嵌套,事件冒泡对动画效果的影响 需求:点击按钮后,打开新的窗口,新窗口总屏幕右侧滑入,然后关闭前一个窗口。 描述: 使用MouseLeftButtonDown来出发这个事件。 xaml   ...
  • 控件由圆形搜索按钮和输入框两部分组成,输入框又设置了内置提示信息,光标点击则消失,前台窗体xaml和输入框样式如下: <UserControl x:Class="SearchTextboxDemo.SearchTextBox" xmlns=...
  • WPF淡入淡出效果

    2013-12-06 17:13:00
    本博客主要是介绍字体输入法之间的动画转换和点击字体...1:click 字体button, 起初选中的那个按钮会有动画效果的来到你点击按钮。 如下面代码: 转载于:https://www.cnblogs.com/xuelan/p/WPF.html...
  • C# WPF动画——小游戏

    2021-01-11 19:49:54
    学了WPF动画,一时兴起写了个小游戏哈哈哈哈哈,被女朋友抢去玩了,代码就不贴了,就写一下思路吧。 1、在XAML上,把按键的形状做成一个米老鼠头的形状,并给这个按键一个RenderTransform的属性,通过点击按钮改变...
  • 用鼠标点击右边的卷轴,动画重复一次,点击“关闭”按钮将退出应用程序。下面介绍制作步骤。 1、窗口设计 新建项目中MainWindow的Window属性: “外观”栏目中,WindowStyle-None,窗口最上方的控制条被...
  • WPF 动画 学习笔记3

    2012-07-21 18:28:07
    会自动计算生成动画效果。 2. Silverlight动画是对象属性的修改过程; 例如,一个按钮动画,用户点击后,按钮会自动增大,其 动画原理,就是对按钮的宽度和高度在一定时间段中进行改变置,即生成动
  • WPF MVVM Image旋转动画

    2014-04-29 07:26:44
    大家好,我现在刚开始学习MVVM模式开发,现在我在ViewModel中申明了一个ImageSource类型的属性,并在View中进行Binding,现在我在界面中加入了一个用于顺时、逆时针旋转的按钮,想通过点击按钮时对图片实行+ -1度的...
  • Wpf实现横向切换页面

    2021-01-20 16:35:56
    在实际项目开发中,我们可能会遇到点击按钮实现切换多个页面的效果,这个时候我们就可以将这多个界面放入一个Orientation为Horizontal的StackPanel当中,点击下一页的时后,里面所有控件执行TranslteTransform动画。...
  • 滥用Effect, 不得将位图效果应用于大型可视对象或动画,因为这样做会降低性能。 不止一次的在这里吃亏,对于性能比较好的机器,是没有问题的,对于性能比较差的机器,简直是灾难,每点击一次按钮都很慢。例如:...
  • 鼠标点击按钮效果。默认值为Classic(其他可选项为Sink)。 BorderCornerRadius CornerRadius 按钮圆角大小。默认值为0。 CoverBrush AnimationStyles枚举 鼠标悬浮时遮罩层的背景颜色(Outline和Link样式下...
  • asp.net知识库

    2015-06-18 08:45:45
    使用microsoft.web.ui.webcontrols的TabStrip与IFame组件,达到页的切换效果 HttpModule 实现 ASP.Net (*.aspx) 中文简繁体的自动转换,不用修改原有的任何代码,直接部署即可! 服务器自定义开发二之客户端脚本回发 Web...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

wpf按钮点击动画效果