zoukankan      html  css  js  c++  java
  • WPF触控程序开发(三)——类似IPhone相册的反弹效果

         用过IPhone的都知道,IPhone相册里,当图片放大到一定程度后,手指一放,会自动缩回,移动图片超出边框后手指一放,图片也会自动缩回,整个过程非常和谐、自然、精确,那么WPF能否做到呢,答案是肯定的。

         在没有现成的控件的情况下,只有自己做,你肯定想到做动画,WPF触屏开发提供了相应的功能来获取触控点的一些变化,这些变化的最佳消费者个人认为是Matrix。我们回想下做动画一般怎么做,比如给一个button做个宽度增5的动画,我们一般是定义一个DoubleAnimation,然后定义一个Sotryboard,然后用Sotryboard的静态方法SetTargetProperty设置UI对象和动画作用的依赖属性。按照这样的步骤,我们给UI的Matrix做动画,发现,找不到这样的一个类似DoubleAnimation的动画类,Matrix也没有类似Button.WidthProperty这样的依赖属性。也许你会说Matrix的属性OffsetX,M11什么的都是double类型,可以对其设置动画,但是Storyboard应用的对象必须是继承自DependencyProperty的,所以是不可能在Matrix的属性上设置动画的,唯一的解决方案是自己做一个类似于MatrixAnimation的东西。网上有人写过这样的动画类,如下:
        public class LinearMatrixAnimation : AnimationTimeline
        {
            public Matrix? From
            {
                set { SetValue(FromProperty, value); }
                get { return (Matrix)GetValue(FromProperty); }
            }
            public static DependencyProperty FromProperty = DependencyProperty.Register("From", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null));
            public Matrix? To
            {
                set { SetValue(ToProperty, value); }
                get { return (Matrix)GetValue(ToProperty); }
            }
            public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null));
            public LinearMatrixAnimation()
            {
            }
            public LinearMatrixAnimation(Matrix from, Matrix to, Duration duration)
            {
                Duration = duration;
                From = from;
                To = to;
            }
            public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
            {
                if (animationClock.CurrentProgress == null)
                {
                    return null;
                }
                double progress = animationClock.CurrentProgress.Value;
                Matrix from = From ?? (Matrix)defaultOriginValue;
                if (To.HasValue)
                {
                    Matrix to = To.Value;
                    Matrix newMatrix = new Matrix(((to.M11 - from.M11) * progress) + from.M11, 0, 0, ((to.M22 - from.M22) * progress) + from.M22,
                                                  ((to.OffsetX - from.OffsetX) * progress) + from.OffsetX, ((to.OffsetY - from.OffsetY) * progress) + from.OffsetY);
                    return newMatrix;
                }
                return Matrix.Identity;
            }
            protected override System.Windows.Freezable CreateInstanceCore()
            {
                return new LinearMatrixAnimation();
            }
            public override System.Type TargetPropertyType
            {
                get { return typeof(Matrix); }
            }
        }
      有了这个类,我们就可以使用了:
    var animation = new LinearMatrixAnimation(oldMatrix, newMatrix, TimeSpan.FromSeconds(0.5));
    animation.AccelerationRatio = 0.3;
    animation.DecelerationRatio = 0.3;
      有了动画,只需要用UI的MatrixTransform启动动画即可,假设某个UI的MatrixTransform为matrixTransform,我们就可以启动了:
    matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, animation);
      有效果,但是貌似只能执行一次,执行完之后,后来无论怎样弄都没反应了,这是由于动画执行完后锁定了属性,网上也有人解决了,办法是在执行完动画之后做了点处理:
    public static void PlayMatrixTransformAnimation(MatrixTransform matrixTransform, Matrix newMatrix, TimeSpan timeSpan)
    {
      var animation = new LinearMatrixAnimation(matrixTransform.Matrix, newMatrix, TimeSpan.FromSeconds(0.5));
      animation.AccelerationRatio = 0.3;
      animation.DecelerationRatio = 0.3;
      animation.FillBehavior = FillBehavior.HoldEnd;
      animation.Completed += (sender, e) =>
      {
        //去除属性的动画绑定  
        matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, null);
        //将期望结果值保留  
        matrixTransform.Matrix = newMatrix;
      };
    
        //启动动画  
        matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, animation, HandoffBehavior.SnapshotAndReplace);
    }

      这样一来,仿IPhone的反弹效果就已经差不多了。其实这里是利用了UI的MatrixTransform做了动画,有人说不是有个MatrixAnimationUsingKeyFrames动画类吗,有兴趣的人可以继续探索下。

      鉴于大家的热情,我会把全部代码整理出来放到群文件共享里,敬请关注。

  • 相关阅读:
    【C#/WPF】限制GridSplitter分隔栏的滑动范围
    【C#】访问泛型中的List列表数据
    【C#学习笔记】反射的简单用法
    【C#】获取泛型<T>的真实类型
    【Unity】关于发射子弹、导弹追踪的逻辑
    【转】【Unity】四元数(Quaternion)和旋转
    【Unity】UGUI的Text各种小问题
    【火狐FireFox】同步失败后,书签被覆盖,如何恢复书签
    【转】【Unity】实现全局管理类的几种方式
    【Unity】动态调用其他脚本的函数
  • 原文地址:https://www.cnblogs.com/zoexia/p/3731429.html
Copyright © 2011-2022 走看看