zoukankan      html  css  js  c++  java
  • UWP中使用Composition API实现吸顶(1)

    前几天需要在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发生关系。

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

    <Page
        x: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。

    var _scrollviewer = FindFirstChild<ScrollViewer>(_listview);
    
    static T FindFirstChild<T>(FrameworkElement element) where T : FrameworkElement
    {
    int childrenCount = VisualTreeHelper.GetChildrenCount(element);
        var children = new FrameworkElement[childrenCount];

    for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement; children[i] = child; if (child is T) return (T)child;
    }
    for (int i = 0; i < childrenCount; i++) if (children[i] != null) { var subChild = FindFirstChild<T>(children[i]); if (subChild != null) return subChild; } return null;
    }

    获取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,但是赋值或者插入数值是会生效的。

  • 相关阅读:
    驯服 Tiger: 并发集合 超越 Map、Collection、List 和 Set
    模块化Java:声明式模块化
    模块化Java:静态模块化
    用 Apache Tika 理解信息内容
    Refactoring: Encapsulate Collection
    新型的几乎万能的数据结构CDO
    CDO数据结构基础(1) 转载
    模块化Java简介(转载infoq)
    模块化Java:动态模块化
    责任链模式(C++)
  • 原文地址:https://www.cnblogs.com/blue-fire/p/6991097.html
Copyright © 2011-2022 走看看