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動畫類嗎,有興趣的人可以繼續探索下。

  鑒於大家的熱情,我會把全部代碼整理出來放到群文件共享里,敬請關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM