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事件中获取。
FlipView flipView;
ScrollViewer scrollViewer;
Compositor compositor;
CompositionPropertySet scrollPropSet; public DependencyObject AssociatedObject { get; private set; } public void Attach(DependencyObject associatedObject)
{
AssociatedObject = associatedObject;
if (associatedObject is FlipView flip) flipView = flip;
else throw new ArgumentException("对象不是FlipView");
scrollViewer = Helper.FindVisualChild<ScrollViewer>(flipView, "ScrollingHost");
if (scrollViewer == null)
{
flipView.Loaded += FlipView_Loaded;
}
else InitCompositionResources(scrollViewer);
} private void FlipView_Loaded(object sender, RoutedEventArgs e)
{
flipView.Loaded -= FlipView_Loaded;
var scroll = Helper.FindVisualChild<ScrollViewer>(flipView, "ScrollingHost");
if (scroll == null) throw new ArgumentNullException("ScrollViewer为空");
else scrollViewer = scroll; InitCompositionResources(scrollViewer);
} void InitCompositionResources(ScrollViewer scroll)
{
if (compositor == null) compositor = ElementCompositionPreview.GetElementVisual(flipView).Compositor;
if (scroll == null) return; scrollPropSet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
}
public static class Helper
{
public static T FindVisualChild<T>(DependencyObject obj, int Index = ) where T : DependencyObject
{
if (Index == -) return null;
int count = VisualTreeHelper.GetChildrenCount(obj);
int findedcount = ;
for (int i = ; i < count; i++)
{
DependencyObject child = Windows.UI.Xaml.Media.VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
{
if (findedcount == Index)
return (T)child;
else
{
findedcount++;
}
}
else
{
T childOfChild = FindVisualChild<T>(child, findedcount);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
public static T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(obj);
int findedcount = ;
for (int i = ; i < count; i++)
{
DependencyObject child = Windows.UI.Xaml.Media.VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
{
if ((child as FrameworkElement).Name == name)
return (T)child;
else
{
findedcount++;
}
}
else
{
T childOfChild = FindVisualChild<T>(child, findedcount);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
}
然后创建两个表达式动画,分别作用在中心点和缩放上。
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附加动画,虽然损失了部分性能,但是可以保证不出问题。
void InitAnimation()
{
if (compositor != null)
{
for (int i = ; i < flipView.Items.Count; i++)
{
var item = flipView.ContainerFromIndex(i);
if (item is UIElement ele)
{
var visual = ElementCompositionPreview.GetElementVisual(ele);
CenterPointAnimation.SetReferenceParameter("visual", visual);
visual.StartAnimation("CenterPoint", CenterPointAnimation);
visual.StopAnimation("Scale.X");
visual.StopAnimation("Scale.Y");
ScaleAnimation.SetReferenceParameter("visual", visual);
visual.StartAnimation("Scale.X", ScaleAnimation);
visual.StartAnimation("Scale.Y", ScaleAnimation);
}
}
}
}
最后在Loaded的最后也调用一次InitAnimation,大功告成。
UWP:使用Behavior实现FlipView简单缩放效果的更多相关文章
- Android 四种简单的动画(淡入淡出、旋转、移动、缩放效果)
最近在Android开发当中,用到的动画效果. public void onClick(View arg0) { // TODO 自动生成的方法存根 switch (arg0.getId()) { c ...
- [UWP]使用Picker实现一个简单的ColorPicker弹窗
在上一篇博文<[UWP]使用Popup构建UWP Picker>中我们简单讲述了一下使用Popup构建适用于MVVM框架下的弹窗层组件Picker的过程.但是没有应用实例的话可能体现不出P ...
- 《JavaScript 实战》:JavaScript 实现拖拽缩放效果
拖拉缩放效果,实现通过鼠标拖动来调整层的面积(宽高)大小,例如选框效果.这里的拖拉缩放比一般的选框复杂一点,能设置八个方位(方向)的固定触发点,能设置最小范围,最大范围和比例缩放. 跟拖放效果一样,程 ...
- web前端学习(三)css学习笔记部分(5)-- CSS动画--页面特效、HTML与CSS3简单页面效果实例
CSS动画--页面特效部分内容目前仅仅观看了解内容,记录简单笔记,之后工作了进行内容的补充 7. CSS动画--页面特效 7.1 2D.3D转换 7.1.1 通过CSS3转换,我们能够对元素进行 ...
- Query 一些简单的效果
Query 一些简单的效果 $(selector).hide(speed,callback); 隐藏 $(selector).show(speed,callback); 显示 $(selector). ...
- 原生JS封装简单动画效果
原生JS封装简单动画效果 一致使用各种插件,有时候对原生JS陌生了起来,所以决定封装一个简单动画效果,熟悉JS原生代码 function animate(obj, target,num){ if(ob ...
- iOS开发——实用技术OC篇&简单抽屉效果的实现
简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一 ...
- HTML与CSS简单页面效果实例
本篇博客实现一个HTML与CSS简单页面效果实例 index.html <!DOCTYPE html> <html> <head> <meta charset ...
- iOS简单动画效果:闪烁、移动、旋转、路径、组合
#define kDegreesToRadian(x) (M_PI * (x) / 180.0) #define kRadianToDegrees(radian) (radian*180.0)/(M_ ...
随机推荐
- 暂停和播放CSS3动画的两种实现方法
1,直接修改animationPlayState <!DOCTYPE html> <html> <head lang="en"> <met ...
- ASP.NET MVC Autofac依赖注入的一点小心得(包含特性注入)
前言 IOC的重要性 大家都清楚..便利也都知道..新的ASP.NET Core也大量使用了这种手法.. 一直憋着没写ASP.NET Core的文章..还是怕误导大家.. 今天这篇也不是讲Core的 ...
- python编程快速上手之第3章实践项目参考答案
1 #!/usr/bin/env python 2 # coding:utf-8 3 # write by mfyang 4 # collatz.py 5 # 从用户读入一个值,并判断这个值是不是一个 ...
- Java基础语法<二> 字符串String
1. 代码点与代码单元 Java字符串由char序列组成.大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示. length()方法将返回采用UTF-16编码表示 ...
- ansible的安装
安装 ansible-server的安装 client需要有python2.5以上 的python server和client都关闭了selinux server端: 网址: http://www.a ...
- 谷歌是如何做代码审查的 | 外刊IT评论 - Google Chrome
谷歌是如何做代码审查的 本文的作者 Mark CC 在上一篇文章中提到过,我已经不在Google工作了.我还没有想清楚应该去哪里-有两三个非常好的工作机会摆在我面前.因为在这段做决 ...
- babel如此简单
凡是看到这个标题点进来的同学,相信对babel都有了一定的了解.babel使用起来很简单,简单到都没有必要写一篇文章去介绍,直接看看官方文档就可以.所以我也在怀疑到底该不该写这篇文章.想来想去还是决定 ...
- Java - extends
继承 一个类得到了另一个类当中的成员变量和成员函数. Java只支持单继承,一个父类可以有多个子类. 使用继承,可减少重复代码.把重复代码放入父类中.需要添加共同的成员变量或函数时可以直接操作父类. ...
- .Net中关于相等的问题
在.Net框架中,如果您查看所有类型的的基类:System.Object类,将找到如下4个与相等判断的方法: static Equals() virtual Equals() static Refer ...
- NOIP模拟:切蛋糕(数学欧拉函数)
题目描述 BG 有一块细长的蛋糕,长度为 n. 有一些人要来 BG 家里吃蛋糕, BG 把蛋糕切成了若干块(整数长度),然后分给这些人. 为了公平,每个人得到的蛋糕长度和必须相等,且必须是连续的一段 ...