WPF路径动画(动态逆向动画)

WPF 中的Path.Data 不再多介绍,M开始坐标点 C弧度坐标点 L 直线坐标点

  <Path x:Name="path0" Data="M 10,100 C 35,0 135,0 160,100 180,190 285,200 310,100" Height="135.32"
                  Stretch="Uniform" Stroke="#FF61E70A" StrokeThickness="2"    HorizontalAlignment="Center" VerticalAlignment="Center" />

  <Path x:Name="path0" Data="M95,50 L324.67997,50 324.67997,119.67997 234.67998,119.67997 234.67998,184.68002
                  344.67999,184.68002 394.68,134.67999 C394.68,134.67999 394.68,189.68005
                  394.68,129.68002 394.68,69.679984 434.68002,89.679985 434.68002,89.679985
                  L477.18005,132.18003 477.18005,164.68004 419.68006,164.6800" Height="135.32"
                  Stretch="Uniform" Stroke="#FF61E70A" StrokeThickness="2"    HorizontalAlignment="Center" VerticalAlignment="Center" />

个人写了关于Path.Data数据反向,意思就是把Path的数据逆转,但是图形是没有变化的

Xaml代码如下:

<Window x:Class="WPFPathReverse.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:WPFPathReverse"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="正向动画" Width="80" Margin="5" Click="btnPositive_Click"></Button>
            <Button Content="反向动画" Width="80" Margin="5" Click="btnRevPositive_Click"></Button>
        </StackPanel>
        <Canvas Grid.Row="1" >
            <Path x:Name="path0" Data="M1,1 L230.67997,1 230.67997,70.67997 140.67998,70.67997 140.67998,135.68002 300.68,85.67999 C300.68,85.67999 300.68,140.68005 300.68,80.68002 300.68,20.679984 340.68002,40.679985 340.68002,40.679985 L383.18005,83.18003 383.18005,115.68004 325.68006,115.68" Height="136.68"
                  Stretch="None" Stroke="#FF61E70A" StrokeThickness="2"  Width="384.18"   />
        </Canvas>

        <Canvas x:Name="canvas" Grid.Row="2"></Canvas>
    </Grid>
</Window>

Code代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFPathReverse
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            string data = this.path0.Data.ToString();
            var result = ConvertReverseData(data);
            Path newpath = new Path();
            newpath.Data = PathGeometry.CreateFromGeometry(Geometry.Parse(result));
            newpath.HorizontalAlignment = HorizontalAlignment.Center;
            newpath.VerticalAlignment = VerticalAlignment.Center;
            newpath.Stretch = this.path0.Stretch;
            newpath.Stroke = new SolidColorBrush(Colors.Red);
            newpath.StrokeThickness = 2;
            newpath.Width = this.path0.Width;
            newpath.Height = this.path0.Height;
            canvas.Children.Add(newpath);
        }

        /// <summary>
        /// 反向Data数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        string ConvertReverseData(string data)
        {
            data = data.Replace("M", "").Replace(" ", "/");
            Regex regex = new Regex("[a-z]", RegexOptions.IgnoreCase);
            MatchCollection mc = regex.Matches(data);
            //item1 从上一个位置到当前位置开始的字符 (match.Index=原始字符串中发现捕获的子字符串的第一个字符的位置。)
            //item2 当前发现的匹配符号(L C Z M)
            List<Tuple<string, string>> tmpList = new List<Tuple<string, string>>();
            int curPostion = 0;
            for (int i = 0; i < mc.Count; i++)
            {
                Match match = mc[i];
                if (match.Index != curPostion)
                {
                    string str = data.Substring(curPostion, match.Index - curPostion);
                    tmpList.Add(new Tuple<string, string>(str, match.Value));
                }
                curPostion = match.Index + match.Length;
                if (i + 1 == mc.Count)//last
                {
                    tmpList.Add(new Tuple<string, string>(data.Substring(curPostion), match.Value));
                }
            }
            //char[] spChar = new char[2] { ‘C‘, ‘L‘ };
            //var tmpList = data.Split(spChar);
            List<string[]> spList = new List<string[]>();
            for (int i = 0; i < tmpList.Count; i++)
            {
                var cList = tmpList[i].Item1.Split(‘/‘);
                spList.Add(cList);
            }
            List<string> strList = new List<string>();
            for (int i = spList.Count - 1; i >= 0; i--)
            {
                string[] clist = spList[i];
                for (int j = clist.Length - 1; j >= 0; j--)
                {
                    if (j == clist.Length - 2)//对于第二个元素增加 L或者C的标识
                    {
                        var pointWord = tmpList[i - 1].Item2;//获取标识
                        strList.Add(pointWord + clist[j]);
                    }
                    else
                    {
                        strList.Add(clist[j]);
                    }
                }
            }
            string reverseData = "M" + string.Join(" ", strList);
            return reverseData;

        }

        private void btnPositive_Click(object sender, RoutedEventArgs e)
        {
            MatrixStory(0, this.path0.Data.ToString());
        }

        private void btnRevPositive_Click(object sender, RoutedEventArgs e)
        {
            string data = this.path0.Data.ToString();
            var result = ConvertReverseData(data);
            MatrixStory(1, result);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="orientation">0正向 1反向</param>
        /// <param name="data">路径数据</param>
        private void MatrixStory(int orientation, string data)
        {
            Border border = new Border();
            border.Width = 10;
            border.Height = 10;
            border.Visibility = Visibility.Collapsed;
            if (orientation==0)
            {
                border.Background = new SolidColorBrush(Colors.Blue);
            }
            else
            {
                border.Background = new SolidColorBrush(Colors.Green);
            }

            this.canvas.Children.Add(border);
            Canvas.SetLeft(border, -border.Width / 2);
            Canvas.SetTop(border, -border.Height / 2);
            border.RenderTransformOrigin = new Point(0.5, 0.5);

            MatrixTransform matrix = new MatrixTransform();
            TransformGroup groups = new TransformGroup();
            groups.Children.Add(matrix);
            border.RenderTransform = groups;
            //NameScope.SetNameScope(this, new NameScope());
            string registname = "matrix" + Guid.NewGuid().ToString().Replace("-", "");
            this.RegisterName(registname, matrix);
            MatrixAnimationUsingPath matrixAnimation = new MatrixAnimationUsingPath();
            matrixAnimation.PathGeometry = PathGeometry.CreateFromGeometry(Geometry.Parse(data));
            matrixAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
            matrixAnimation.DoesRotateWithTangent = true;//旋转
            //matrixAnimation.FillBehavior = FillBehavior.Stop;
            Storyboard story = new Storyboard();
            story.Children.Add(matrixAnimation);
            Storyboard.SetTargetName(matrixAnimation, registname);
            Storyboard.SetTargetProperty(matrixAnimation, new PropertyPath(MatrixTransform.MatrixProperty));

            #region 控制显示与隐藏
            ObjectAnimationUsingKeyFrames ObjectAnimation = new ObjectAnimationUsingKeyFrames();
            ObjectAnimation.Duration = matrixAnimation.Duration;
            DiscreteObjectKeyFrame kf1 = new DiscreteObjectKeyFrame(Visibility.Visible, TimeSpan.FromMilliseconds(1));
            ObjectAnimation.KeyFrames.Add(kf1);
            story.Children.Add(ObjectAnimation);
            //Storyboard.SetTargetName(border, border.Name);
            Storyboard.SetTargetProperty(ObjectAnimation, new PropertyPath(UIElement.VisibilityProperty));
            #endregion
            story.FillBehavior = FillBehavior.Stop;
            story.Begin(border, true);
        }
    }
}

执行效果如下:

写这个Path反转的目的是动态生成动画的时候,可以逆向执行动画,而不必为逆向动画重新画一个Path.

源代码下载

时间: 2024-10-17 23:52:51

WPF路径动画(动态逆向动画)的相关文章

WPF学习之绘图和动画

如今的软件市场,竞争已经进入白热化阶段,功能强.运算快.界面友好.Bug少.价格低都已经成为了必备条件.这还不算完,随着计算机的多媒体功能越来越强,软件的界面是否色彩亮丽.是否能通过动画.3D等效果是否吸引用户的眼球也已经成为衡量软件的标准. 软件项目成功的三个要素是:资源.成本.时间.无论是为了在竞争中保持不败还是为了激发起用户对软件的兴趣,提高软件界面的美化程度.恰当的将动画和3D等效果引入应用程序都是一个必然趋势.然而使用传统的桌面应用程序开发工具和框架(如Winform.MFC.VB.D

《深入浅出WPF》笔记——绘画与动画

<深入浅出WPF>笔记——绘画与动画 本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一下学习的过程.在本记录中,为了更好的理解绘画与动画,多数的例子还是在VS里面敲出来的.好了,不废话了,现在开始. 一.WPF绘画 1.1基本图形 在WPF中可以绘制矢量图,不会随窗口或图型的放大或缩小出现锯齿或变形,除此之外,XAML绘制出来的图有个好处就是便于修改,当图不符合要求的时间,通常改某些属性就可以完成

WPF 一个弧形手势提示动画

这是一个操作提示动画,一个小手在屏幕上按照一个弧形来回运动<Window x:Class="LZRichMediaWall.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:LocWindow="clr-n

segment-实现SVG路径描边绘制与动画的轻量库

今天来一起了解一个实现SVG路径描边绘制与动画的轻量级类库segment,我们从轻松上手.使用详解.资源和案例.源码解读等几个方面进行介绍. 1. 轻松上手 html方面添加segment,定义path. <script src="/dist/segment.min.js"></script> <svg> <path id="my-path" ...> </svg> JS方面利用path实例化一个segme

WPF编游戏系列 之六 动画效果(1)

原文:WPF编游戏系列 之六 动画效果(1)        本篇主要针对界面进行动画效果处理.首先在打开或关闭界面时,使其产生动态效果而不是生硬的显示或消失(如下图).其次在鼠标放到关闭窗口图标上时,使其出现闪动效果.下面将通过Storyboard和EventTrigger实现这些效果.     1. 先从简单的入手吧,为关闭图标增加闪动效果,首先要在ScrollViewer中添加一个关闭窗口图标. ... ... <ScrollViewer Name="queryScrollViewer

C# WPF 简单自定义菜单切换动画

微信公众号:Dotnet9,网站:Dotnet9,问题或建议,请网站留言: 如果您觉得Dotnet9对您有帮助,欢迎赞赏 C# WPF 简单自定义菜单切换动画 内容目录 实现效果 业务场景 编码实现 本文参考 源码下载 1.实现效果 自定义菜单切换动画 2.业务场景 菜单切换动画 3.编码实现 3.1 添加Nuget库 使用 .Net Core 3.1 创建名为"CustomMenu"的WPF解决方案,添加两个Nuget库:MaterialDesignThemes和MaterialDe

*C#(WPF)--矩阵拖动和矩阵动画(拖动展开,不足动画效果)

最近在研发新的项目,遇到了一个桌面模式下的难点--展开动画.之前动画这方面没做过,也许很多人开始做的时候也会遇到相关问题,因此我把几个重点及实际效果图总结展示出来: 我的开发环境是在VS2017下进行的,这个工具条主要功能是:一个工具条,可进行拖拉.可进行拖拉展开,可在拖动之后不足展开并反向继续展开剩下的部分: 一.[拖动]   拖动的核心代码是通过矩阵进行定位和拖动的,定位是以父容器为模板的.以下是核心代码(及效果图): 1 /// <summary> 2 /// 这里TitleBar代指最

iOS:核心动画之关键帧动画CAKeyframeAnimation

CAKeyframeAnimation——关键帧动画 关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是: –CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值 – 属性说明: –values:上述的NSArray对象.里面的元素称为“关键帧”(keyframe).动画对象会在指定的时间(duration)内,依次显

ios开发核心动画七:核心动画与UIView动画的区别

/** UIView与核心动画区别?(掌握) 1.核心动画只作用在layer. 2.核心动画看到的都是假像,它并没有去修改UIView的真实位置. 什么时候使用核心动画? 1.当不需要与用户进行交互,使用核心动画 2.当要根据路径做动画时,使用核心动画:CABasicAnimation,CAKeyFrameAnimation,两个都可以根据绘制的路径UIBizerPath来绘制路径来执行动画 3.当做转场动画时, 使用核心动画 (核心动画转场类型比较多)CATrasition或是UIView的核