UWP:使用Behavior实现FlipView简单缩放效果

先上效果图

首先安装Behavior SDK:在Nuget中搜索安装 Microsoft.Xaml.Behaviors.Uwp.Managed 。

然后新建类,AnimationFlipViewBehavior.cs,并继承DependencyObject和IBehavior接口:

namespace TestBehavior
{
    public class AnimationFlipViewBehavior: DependencyObject, IBehavior
    {
        public DependencyObject AssociatedObject { get; set; }
        public void Attach(DependencyObject associatedObject)
        {
            AssociatedObject  = associatedObject;
        }
        public void Detach()
        {

        }
    }
}

Attach是添加Behavior时被调用的方法,Detach是移除Behavior时被调用的方法。

这时在Attach中判断是否是FlipView,并且保存下来。然后按照老样子获取ScrollViewer,如果FlipView已经加载好了,就可以直接获取到ScrollViewer,否则要在FlipView的Loaded事件中获取。

 1 FlipView flipView;
 2 ScrollViewer scrollViewer;
 3 Compositor compositor;
 4 CompositionPropertySet scrollPropSet;
 5
 6 public DependencyObject AssociatedObject { get; private set; }
 7
 8 public void Attach(DependencyObject associatedObject)
 9 {
10     AssociatedObject = associatedObject;
11     if (associatedObject is FlipView flip) flipView = flip;
12     else throw new ArgumentException("对象不是FlipView");
13     scrollViewer = Helper.FindVisualChild<ScrollViewer>(flipView, "ScrollingHost");
14     if (scrollViewer == null)
15     {
16         flipView.Loaded += FlipView_Loaded;
17     }
18     else InitCompositionResources(scrollViewer);
19 }
20
21 private void FlipView_Loaded(object sender, RoutedEventArgs e)
22 {
23     flipView.Loaded -= FlipView_Loaded;
24     var scroll = Helper.FindVisualChild<ScrollViewer>(flipView, "ScrollingHost");
25     if (scroll == null) throw new ArgumentNullException("ScrollViewer为空");
26     else scrollViewer = scroll;
27
28     InitCompositionResources(scrollViewer);
29 }
30
31 void InitCompositionResources(ScrollViewer scroll)
32 {
33     if (compositor == null) compositor = ElementCompositionPreview.GetElementVisual(flipView).Compositor;
34     if (scroll == null) return;
35
36     scrollPropSet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
37 }

 1 public static class Helper
 2 {
 3     public static T FindVisualChild<T>(DependencyObject obj, int Index = 0) where T : DependencyObject
 4     {
 5         if (Index == -1) return null;
 6         int count = VisualTreeHelper.GetChildrenCount(obj);
 7         int findedcount = 0;
 8         for (int i = 0; i < count; i++)
 9         {
10             DependencyObject child = Windows.UI.Xaml.Media.VisualTreeHelper.GetChild(obj, i);
11             if (child != null && child is T)
12             {
13                 if (findedcount == Index)
14                     return (T)child;
15                 else
16                 {
17                     findedcount++;
18                 }
19             }
20             else
21             {
22                 T childOfChild = FindVisualChild<T>(child, findedcount);
23                 if (childOfChild != null)
24                     return childOfChild;
25             }
26         }
27         return null;
28     }
29     public static T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
30     {
31         int count = VisualTreeHelper.GetChildrenCount(obj);
32         int findedcount = 0;
33         for (int i = 0; i < count; i++)
34         {
35             DependencyObject child = Windows.UI.Xaml.Media.VisualTreeHelper.GetChild(obj, i);
36             if (child != null && child is T)
37             {
38                 if ((child as FrameworkElement).Name == name)
39                     return (T)child;
40                 else
41                 {
42                     findedcount++;
43                 }
44             }
45             else
46             {
47                 T childOfChild = FindVisualChild<T>(child, findedcount);
48                 if (childOfChild != null)
49                     return childOfChild;
50             }
51         }
52         return null;
53     }
54 }

然后创建两个表达式动画,分别作用在中心点和缩放上。

ExpressionAnimation CenterPointAnimation;
ExpressionAnimation ScaleAnimation;

void InitCompositionResources(ScrollViewer scroll)
{
    if (compositor == null) compositor = ElementCompositionPreview.GetElementVisual(flipView).Compositor;
    if (scroll == null) return;

    scrollPropSet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
    if (CenterPointAnimation == null)
    {
        CenterPointAnimation = compositor.CreateExpressionAnimation("Vector3(visual.Size.X/2,visual.Size.Y/2,0)");
    }
    if (ScaleAnimation == null)
    {
        ScaleAnimation = compositor.CreateExpressionAnimation("Clamp(1- (visual.Offset.X + scroll.Translation.X) / visual.Size.X * 0.4, 0f, 1f)");
        ScaleAnimation.SetReferenceParameter("scroll", scrollPropSet);
    }
}

这里着重说一下ScaleAnimation。

表达式中的Clamp(value,min,max)是内置函数,当value在min和max之间的时候返回value,小于min则返回min,大于max则返回max。

FlipView中是一个ScrollViewer,横向滚动,ScrollViewer内的元素的Visual.Offset.X控制Visual的位置,而不是默认为0。所以只要判断visual.Offset.X和scroll.Translation.X的关系,就能做出动画来。

然后写一个方法,给所有Items的容器附加上这些动画。

因为默认的Items并不是Observable的,有两种解决方案,一是设置ItemsSource为一个ObservableCollection,然后注册CollectionChanged事件。这样做会让控件和页面后台代码耦合度提升。为了更干净的代码结构,这里用一个性能低一些的方法,注册FlipView的SelectionChanged事件,在这里调用InitAnimation方法。

如果每次只给SelectedItem和左右的Item附加动画,PC上测试很完美,但是手机上,或者说触摸操作的时候,会出现动画未加载的问题。这里涉及到一个FlipView和Pivot的大坑。

在键鼠操作和代码操作SelectedIndex切换页面的时候,是先触发SelectionChanged事件,再播放动画的。但是触摸操作的时候,只有当你滑屏再送手后,系统才知道到底应不应该切换页面。所以我们每次送手播放完动画和触发SelectionChanged并不同步,动画自然就不会附加到后面的Item上,所以每次我们都给所有的Item附加动画,虽然损失了部分性能,但是可以保证不出问题。

 1 void InitAnimation()
 2 {
 3     if (compositor != null)
 4     {
 5         for (int i = 0; i < flipView.Items.Count; i++)
 6         {
 7             var item = flipView.ContainerFromIndex(i);
 8             if (item is UIElement ele)
 9             {
10                 var visual = ElementCompositionPreview.GetElementVisual(ele);
11                 CenterPointAnimation.SetReferenceParameter("visual", visual);
12                 visual.StartAnimation("CenterPoint", CenterPointAnimation);
13                 visual.StopAnimation("Scale.X");
14                 visual.StopAnimation("Scale.Y");
15                 ScaleAnimation.SetReferenceParameter("visual", visual);
16                 visual.StartAnimation("Scale.X", ScaleAnimation);
17                 visual.StartAnimation("Scale.Y", ScaleAnimation);
18             }
19         }
20     }
21 }

最后在Loaded的最后也调用一次InitAnimation,大功告成。

源代码下载

时间: 2024-10-25 12:07:47

UWP:使用Behavior实现FlipView简单缩放效果的相关文章

Android 四种简单的动画(淡入淡出、旋转、移动、缩放效果)

最近在Android开发当中,用到的动画效果. public void onClick(View arg0) { // TODO 自动生成的方法存根 switch (arg0.getId()) { case R.id.danru://淡入淡出 AnimationSet aset=new AnimationSet(true); AlphaAnimation aa=new AlphaAnimation(1,0); aa.setDuration(2000); aset.addAnimation(aa)

手把手教导航头像缩放效果

引言 今天抽时间教大家实现一个非常常见的效果.跟着笔者一起来学习,实现起来非常简单,只需要几行代码即可! 在很多的App中经常有上下滚动时用户头像也跟着变化,而用户头像是放在系统的导航条上的.可能有朋友们尝试过自定义导航view,其实没有必要,直接使用系统自带的导航即可! 通过本篇文章,您将学习以下知识点: 如何分析实现原理 如何实现缩放效果 如何将计算缩放系数 效果图 在开始讲解原理之前,还是先上效果图.有图有真相,才能帮助大家阅读,提升阅读的效果.如下图所示,在往下滚动时,在一定范围内会放大

[UWP]使用Picker实现一个简单的ColorPicker弹窗

在上一篇博文<[UWP]使用Popup构建UWP Picker>中我们简单讲述了一下使用Popup构建适用于MVVM框架下的弹窗层组件Picker的过程.但是没有应用实例的话可能体现不出Picker相对于ContentDialog的优点在哪里,毕竟Linus大神说过: Talk is cheap, show me the code! 我们假定要实现这样一个颜色选择器:当用户需要选择一个颜色时,应用弹出颜色选择器,用户选择完成后,点击"确定"按钮关闭弹窗,并且向调用方代码返回

jQuery实现的图片等比例缩放效果

jQuery实现的图片等比例缩放效果:如果一个容器中放一个比容器还要大的图,那就可能就造成布局出现问题,就算是不容器大,有时候也看起来不够美观,这时候就要限制图片的尺寸,当然不能变形,否则就难看了,下面就介绍一下如何使用jQuery实现等比例缩放效果.代码如下: <div id="demo"> <img src="a.jpg" width="800" height="300" alt="图片&quo

iOS开发——实用技术OC篇&amp;简单抽屉效果的实现

简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一些功夫了,我们这里知识简单的介绍怎么去实现,不过一般我们开发都是找别人做好的,也没必要烂肺时间,除非你真的是大牛或者闲的蛋疼. 其实关于抽屉效果就是界面有三个View,其实一个主View其他两个分别是左边和右边的View,我们分别为他们添加手势,实现左右滑动显示对应的View. 一:所以,首先我们需

自定义实现ExpandableListView收缩的简单动画效果

以下是 ExpandableListView 收缩的简单动画效果 1 /* 2 * Copyright (C) 2014 Gary Guo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the L

Cocos2dx 小技巧(十四)ScrollView实现缩放效果

这阶段心绪比較乱,所以这篇开头就不扯淡了.(谁说大姨夫来了我跟谁急!~~)说到大姨夫我突然想到英雄联盟有个美女讲解叫伊芙蕾亚,她的堂弟ID居然叫:姨夫累呀,好笑吧(呵呵,有点冷~~额,我都说不扯淡了).------------前天有个网友问我一些关于scrollView的使用方法,因为在QQ上实在讲不清,所以就利用晚上的时间写这篇博客出来了.本篇要实现的功能是用scrollView 拖动对象时,对象移动到某个固定范围会有放大.缩小的效果.以下開始.在进入正题前我先简短的介绍下scrollView

java实现的图片缩放 压缩 裁剪工具!找了很久,市面上再也找不到比它缩放效果还好的代码了

原文:java实现的图片缩放 压缩 裁剪工具!找了很久,市面上再也找不到比它缩放效果还好的代码了 源代码下载地址:http://www.zuidaima.com/share/1550463380458496.htm 纯 java 实现的 图片缩放 压缩 裁剪工具!不依赖任何第三方 jar 包 1. 找了很久,市面上再也找不到比它缩放效果还好的代码了 (再不使用任何第三方组件的前提下) 2. 支持缩放 3. 支持剪切 (例如:用户上传头像后剪切成正方形小图) /* * Copyright 2012

js网站轮播图怎么做如何做?鸡哥教你简单制作效果炫酷

日了狗啦,刚刚鸡哥辛苦码了那么多字全丢了又要重新写,这是第二遍写了...今天鸡哥给小白写个不需要写js原生代码,只需要几个插件和一段通俗易懂得jquery代码就能搞定的轮播图,当然js原生代码写着也不算很繁琐,但是有些浪费时间,更何况很多人并不会用js直接写包括鸡哥,当年在学校还是研究过一段时间js的,当时还独自写了一个轮播图俘获了多少同班妹子的芳心,不过现在是基本废了,这东西要常写,不然忘的很快. 唉,本来还有妹子等着鸡哥呢,我这一大意文章丢了,重新写的话估计来不及了,先打个电话让妹子回家吧~