前几天需要在UWP中实现吸顶,就在网上找了一些文章:

吸顶大法 -- UWP中的工具栏吸顶的实现方式之一

在UWP中页面滑动导航栏置顶

发现前人的实现方式大多是控制ListViewBase的Header变换高度,或者建立一个ScrollViewer在里面放置ListViewBase。经过测试,这两种方法或多或少的都有问题。所以我想试试用Composition API实现吸顶的效果。

首先先了解一下Composition API是什么。

Windows.UI.Composition 是可以从任何通用 Windows 平台 (UWP) 应用程序调用的声明性保留模式 API ,从而可以直接在应用程序中创建合成对象、 动画和效果。 该 API 是对诸如 XAML 等现有框架的一个强大补充,从而为 UWP 应用程序开发人员提供了一个熟悉的 C# 图面以供添加到其应用程序。 这些 API 还可以用于创建 DX 样式框架较少的应用程序。

XAML 开发人员可以使用 WinRT“下拉”到采用 C# 的合成层,以便在该合成层上执行自定义工作,而无需一直下拉到图形层并针对任何自定义 UI 工作使用 DirectX 和 C++。 此技术可用于使用合成 API 对现有元素进行动画处理,也可用于通过在 XAML 元素树内创建 Windows.UI.Composition 内容的“视觉岛”来增加 UI。

只看这几句微软给的介绍也是云里来雾里去的,还是看代码吧。

CompositionAPI中有一种动画叫表达式动画。大致效果就是让一个Visual或者PropertySet的属性随着自身另一个属性,或者另一个Visual或者PropertySet的属性的变化而变化。

对于不含Pivot的简单情况,就有这样一个基本的思路了:

  1. 获取到ListViewBase的ScrollViewer;

  2. 获取到ScrollViewer的ManipulationPropertySet和ListViewHeader的Visual;

  3. 让ManipulationPropertySet和Visual发生关系。

我们先来建立一个简单的页面。

<Pagex:Class="TestSwipeBack.ScrollTest"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:TestSwipeBack"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d" Loaded="Page_Loaded"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><ListView x:Name="_listview" ItemsSource="{x:Bind ItemSource,Mode=OneWay}"><ListView.Header><Grid x:Name="_header"><Grid.RowDefinitions><RowDefinition Height="100" /><RowDefinition Height="50" /></Grid.RowDefinitions><Grid Background="LightBlue"><Button>123</Button><TextBlock FontSize="25" HorizontalAlignment="Center" VerticalAlignment="Center">我会被隐藏</TextBlock></Grid><Grid Background="Pink" Grid.Row="1"><Button>123</Button><TextBlock FontSize="25" HorizontalAlignment="Center" VerticalAlignment="Center">我会吸顶</TextBlock></Grid></Grid></ListView.Header><ListView.ItemTemplate><DataTemplate><TextBlock Text="{Binding }" /></DataTemplate></ListView.ItemTemplate></ListView></Grid></Page>

原本ListViewBase里Header是在ItemsPanelRoot下方的,使用Canvans.SetZIndex把ItemsPanelRoot设置到下方。

Canvas.SetZIndex(_listview.ItemsPanelRoot, -1);

然后在后台获取ListView内的ScrollViewer。

 _scrollviewer = FindFirstChild<ScrollViewer> T FindFirstChild<T>(FrameworkElement element)  childrenCount = children =  ( i = ; i < childrenCount; i++ child = VisualTreeHelper.GetChild(element, i) = (child  ( i = ; i < childrenCount; i++ (children[i] !=  subChild = FindFirstChild<T> (subChild !=

获取ListViewHeader的Visual和ScrollViewer的ManipulationPropertySet。

var _headerVisual = ElementCompositionPreview.GetElementVisual(_header);var _manipulationPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(_scrollviewer);

创建表达式动画,然后运行。

var _compositor = Window.Current.Compositor;var _headerAnimation = _compositor.CreateExpressionAnimation("_manipulationPropertySet.Translation.Y > -100f ? 0: -100f -_manipulationPropertySet.Translation.Y");//_manipulationPropertySet.Translation.Y是ScrollViewer滚动的数值,手指向上移动的时候,也就是可视部分向下移动的时候,Translation.Y是负数。_headerAnimation.SetReferenceParameter("_manipulationPropertySet", _manipulationPropertySet);_headerVisual.StartAnimation("Offset.Y", _headerAnimation);

现在滑动Demo看看,是不是在滚动100像素之后,Header就停住了?

注:在一个Visual或者propertySet被附加了动画(即StartAnimation或者StartAnimationGroup)之后,取出(propertySet.TryGetScalar)相应的属性就只能取到0,但是赋值或者插入数值是会生效的。

更多相关文章

  1. 用Shape做动画实例代码
  2. ASP.NET Core 应用程序发布命令实例
  3. Asp.net Core应用程序在Linux上部署的图文详解
  4. ASP.NET Core应用程序运行Vue并且部署在IIS上的详解
  5. c语言代码如何实现贪吃蛇动画
  6. 用XSL翻译Web服务应用程序
  7. 详解XML与现代CGI应用程序的示例代码
  8. 气象XML数据源应用程序的详细解析
  9. 在xml中写动画的实例详解

随机推荐

  1. android虚拟器启动慢的问题
  2. eclipse开发Android必备环境搭建
  3. Android下的单元测试
  4. Android(安卓)图片压缩也即生成缩略图方
  5. Android NDK环境配置与开发
  6. Android自定义控件进阶-打造Android自定
  7. [置顶] Android webview开发中 js与andro
  8. 《宅男的android开发指南》(翻译)--7
  9. Android的Apk签名方案
  10. maxEms和maxLength的区别以及maxEms不起