先上效果图

首先安装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简单缩放效果的更多相关文章

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

    最近在Android开发当中,用到的动画效果. public void onClick(View arg0) { // TODO 自动生成的方法存根 switch (arg0.getId()) { c ...

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

    在上一篇博文<[UWP]使用Popup构建UWP Picker>中我们简单讲述了一下使用Popup构建适用于MVVM框架下的弹窗层组件Picker的过程.但是没有应用实例的话可能体现不出P ...

  3. 《JavaScript 实战》:JavaScript 实现拖拽缩放效果

    拖拉缩放效果,实现通过鼠标拖动来调整层的面积(宽高)大小,例如选框效果.这里的拖拉缩放比一般的选框复杂一点,能设置八个方位(方向)的固定触发点,能设置最小范围,最大范围和比例缩放. 跟拖放效果一样,程 ...

  4. web前端学习(三)css学习笔记部分(5)-- CSS动画--页面特效、HTML与CSS3简单页面效果实例

    CSS动画--页面特效部分内容目前仅仅观看了解内容,记录简单笔记,之后工作了进行内容的补充 7.  CSS动画--页面特效 7.1  2D.3D转换 7.1.1  通过CSS3转换,我们能够对元素进行 ...

  5. Query 一些简单的效果

    Query 一些简单的效果 $(selector).hide(speed,callback); 隐藏 $(selector).show(speed,callback); 显示 $(selector). ...

  6. 原生JS封装简单动画效果

    原生JS封装简单动画效果 一致使用各种插件,有时候对原生JS陌生了起来,所以决定封装一个简单动画效果,熟悉JS原生代码 function animate(obj, target,num){ if(ob ...

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

    简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一 ...

  8. HTML与CSS简单页面效果实例

    本篇博客实现一个HTML与CSS简单页面效果实例 index.html <!DOCTYPE html> <html> <head> <meta charset ...

  9. iOS简单动画效果:闪烁、移动、旋转、路径、组合

    #define kDegreesToRadian(x) (M_PI * (x) / 180.0) #define kRadianToDegrees(radian) (radian*180.0)/(M_ ...

随机推荐

  1. SQL显示某月全部日期明细以及SQL日期格式

    SQL显示某月全部日期明细<存储过程> 方法一: declare @date datetime declare @end datetime ,getdate()) ,@date) crea ...

  2. SharePoint 2013 安装

    步骤 1:打开提升的 SharePoint 2013 命令行管理程序 选择与您的服务器操作系统对应的过程. 在 Windows Server 2008 R2 中 单击“开始”>“所有程序”> ...

  3. servlet+jsp导入Excel到mysql数据库

    package khservlet; import java.io.FileInputStream;import java.io.IOException;import java.io.InputStr ...

  4. 快学Scala之继承

        ## 1. 继承 Scala语言通过 extends 关键字来继承类. 那么继承一个类有什么好处呢? 子类除了拥有继承自超类的方法和字段(即为val(常量), var(变量)所定义的), 还可 ...

  5. 【前端】用jQuery实现瀑布流效果

    jQuery实现瀑布流效果 何为瀑布流: 瀑布流,又称瀑布流式布局.是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部.最早 ...

  6. Spring和SpringMVC父子的容器之道---[上篇]

    Spring和SpringMVC作为Bean管理容器和MVC层的默认框架,已被众多WEB应用采用,而在实际开发中,由于有了强大的注解功能,很多基于XML的配置方式已经被替代,但在实际项目中,我们经常会 ...

  7. C++学习(七)入门篇——C++算数运算符

    以下介绍5种C++基本运算符 +.-.×./.% 注意/为第一个数除以第二个数,结果为商的整数部分,小数部分被丢弃 %求模,两个操作数必须是整型,它生成第一个数除以第二个数的余数 如果其中一个是负数, ...

  8. Java内存区域与对象创建过程

    一.java内存区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则 ...

  9. 【D3】transition API

    摘要: 动画类API 一.API 使用 1. 1 d3.ease 1.2 d3.timer Start a custom animation timer, invoking the specified ...

  10. MySQL学习笔记(一):SQL基础

    定义:SQL即Structure Query Language(机构化查询语言)的缩写,是使用关系数据库的应用语言. 包括三个类别: (1):DDL(Data Definition Language) ...