旗下导航:搜·么
当前位置:网站首页 > .Net教程 > 正文

UWP中运用Composition API完成吸顶的引见(二)【C#.Net教程】,Composition,api,吸顶,实现,使用

作者:搜教程发布时间:2019-11-27分类:.Net教程浏览:108评论:0


导读:在上一篇中我们议论了不触及Pivot的吸顶操纵,然则一般来说,吸顶的部份都是Pivot的Header,所以在此我们将议论关于Pivot多个Item关联同一个Header的状况。...
在上一篇中我们议论了不触及Pivot的吸顶操纵,然则一般来说,吸顶的部份都是Pivot的Header,所以在此我们将议论关于Pivot多个Item关联同一个Header的状况。

老样子,先做一个简朴的页面,页面有一个Grid当Header,一个去掉了头部的Pivot,Pivot内有三个ListView,ListView设置了和页面Header高度一致的空缺Header。

<Pagex:Class="TestListViewHeader.TestHeader2"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:TestListViewHeader"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Pivot ItemsSource="{x:Bind ItemSource}" x:Name="_pivot" SelectionChanged="_pivot_SelectionChanged" ><Pivot.Template>               <!--太长在这儿就不贴了--></Pivot.Template><Pivot.HeaderTemplate><DataTemplate></DataTemplate></Pivot.HeaderTemplate><Pivot.ItemTemplate><DataTemplate><ListView ItemsSource="{Binding }"><ListView.Header><Grid Height="150" /></ListView.Header><ListView.ItemTemplate><DataTemplate><TextBlock Text="{Binding }" /></DataTemplate></ListView.ItemTemplate></ListView></DataTemplate></Pivot.ItemTemplate></Pivot><Grid Height="150" VerticalAlignment="Top" x:Name="_header"><Grid.RowDefinitions><RowDefinition Height="100" /><RowDefinition Height="50" /></Grid.RowDefinitions><Grid Background="LightBlue"><TextBlock FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center">我会被隐蔽</TextBlock></Grid><Grid Grid.Row="1"><ListBox SelectedIndex="{x:Bind _pivot.SelectedIndex,Mode=TwoWay}" ItemsSource="{x:Bind ItemSource}"><ListBox.ItemTemplate><DataTemplate><Grid><TextBlock Text="{Binding Title}" /></Grid></DataTemplate></ListBox.ItemTemplate><ListBox.ItemsPanel><ItemsPanelTemplate><VirtualizingStackPanel Orientation="Horizontal" /></ItemsPanelTemplate></ListBox.ItemsPanel></ListBox></Grid></Grid></Grid></Page>

Pivot的模板太长在这儿就不写了,须要的话,找个体系内置的画笔资本按F12翻开generic.xaml,然后搜刮Pivot就是了,其他控件的模板也能经由过程这个要领猎取。

模板里修正这几句就能够去掉头部:

<PivotPanel x:Name="Panel" VerticalAlignment="Stretch"><Grid x:Name="PivotLayoutElement"><Grid.RowDefinitions><RowDefinition Height="0" /><RowDefinition Height="*" /><!--太长不写--></Grid.RowDefinitions>

然后是背景代码,这里还会用到上一篇的FindFirstChild要领,在这儿就不贴出来了。

老样子,全局的_headerVisual,最幸亏Page的Loaded事宜里初始化我们所须要的这些变量,我偷懒了,直接放到了下面的UpdateAnimation要领里。
然后我们写一个UpdateAnimation要领,用来在PivotItem切换的时刻更新动画的参数。

先推断下假如未选中页就return,然后猎取到当前选中项的容器,再像上次一样从容器里猎取ScrollViewer,不过这里有个坑,稍后再说。

void UpdateAnimation()
{if (_pivot.SelectedIndex == -1) return;var SelectionItem = _pivot.ContainerFromIndex(_pivot.SelectedIndex) as PivotItem;if (SelectionItem == null) return;var _scrollviewer = FindFirstChild<ScrollViewer>(SelectionItem);if (_scrollviewer != null)
    {
        _headerVisual = ElementCompositionPreview.GetElementVisual(_header);var _manipulationPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(_scrollviewer);var _compositor = Window.Current.Compositor;var line = _compositor.CreateCubicBezierEasingFunction(new System.Numerics.Vector2(0, 0), new System.Numerics.Vector2(0.6f, 1));var _headerAnimation = _compositor.CreateExpressionAnimation("_manipulationPropertySet.Translation.Y > -100f ? _manipulationPropertySet.Translation.Y: -100f");
        _headerAnimation.SetReferenceParameter("_manipulationPropertySet", _manipulationPropertySet);
        _headerVisual.StartAnimation("Offset.Y", _headerAnimation);
    }
}

然后在Pivot的SelectionChanged事宜里更新动画:

private void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    UpdateAnimation();
}

点下运转,高低滑一下,并没有随着动。摆布切换一下以后,发如今第二次切换到PivotItem的时刻就能够够随着动了,下断看到第一次运转到"var _scrollviewer = FindFirstChild<ScrollViewer>(SelectionItem);"的时刻_scrollviewer为null。想了良久才意想到,是否是控件没有Loaded的题目,所以才取不到子控件?说改就改。

void UpdateAnimation()
{if (_pivot.SelectedIndex == -1) return;var SelectionItem = _pivot.ContainerFromIndex(_pivot.SelectedIndex) as PivotItem;if (SelectionItem == null) return;var _scrollviewer = FindFirstChild<ScrollViewer>(SelectionItem);if (_scrollviewer != null)
    {
        _headerVisual = ElementCompositionPreview.GetElementVisual(_header);var _manipulationPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(_scrollviewer);var _compositor = Window.Current.Compositor;var line = _compositor.CreateCubicBezierEasingFunction(new System.Numerics.Vector2(0, 0), new System.Numerics.Vector2(0.6f, 1));var _headerAnimation = _compositor.CreateExpressionAnimation("_manipulationPropertySet.Translation.Y > -100f ? _manipulationPropertySet.Translation.Y: -100f");
        _headerAnimation.SetReferenceParameter("_manipulationPropertySet", _manipulationPropertySet);
        _headerVisual.StartAnimation("Offset.Y", _headerAnimation);
    }elseSelectionItem.Loaded += (s, a) =>{
            UpdateAnimation();
        };
}

再次运转,随着动了。然则另有个题目,在每次切换的时刻,Header都邑回归原位一次。这又是一个坑。
猜想在切换PivotItem的时刻,_manipulationPropertySet.Translation.Y会有一个霎时变成0。我踩过的坑人人就不要再踩了。
尝试更新动画前先住手动画。

private void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    _headerVisual?.StopAnimation("Offset.Y");
    UpdateAnimation();
}

运转,果真失利了。
这时候灵光一闪,动画播放时须要时候的啊!这个切换的动画大概是五步:

  1. 触发SelectionChanged;

  2. 页面左移而且逐步消逝;

  3. 卸载页面;

  4. 装载新页面;

  5. 页面从右边挪动到中间而且逐步展现。

第一步最先之前触发了SelectionChanged,然后住手动画,更新动画,我表达式动画都最先播放了,他的第一步还慢悠悠的没有走完...
简朴,在SelectionChanged里加延时,就能够处理(是吗)Header归位的题目(这里又埋下一个坑):

private async void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    _headerVisual?.StopAnimation("Offset.Y");await Task.Delay(180);
    UpdateAnimation();
}

运转,很圆满。然后在手机上试了一下,差点哭了。
关于点击和触摸两种操纵体式格局,切换页时触发事宜和播放动画的递次不一样!
触摸形成的切换页,大概是以下几步:

  1. 滑动形成页面位移,放手后页面左移而且逐步消逝

  2. 触发SelectionChanged;

  3. 卸载页面;

  4. 装载新页面;

  5. 页面从右边挪动到中间而且逐步展现。

但是页面消逝后_manipulationPropertySet.Translation.Y会有一霎时变成0啊!这时候刻的我真的是崩溃的,不过末了照样给我想出了处理方案。
_manipulationPropertySet.Translation.Y变成0的时刻不睬他不就好了,不能再机灵。如许也不须要SelectionChanged里写延时了,觉得本身的代码一会儿变得文雅了许多呢。
修正_headerAnimation的表达式:

 _headerAnimation = _compositor.CreateExpressionAnimation(

注:个中max,min,clamp都是表达式动画中内置的函数,相干的信息能够检察附录。

再举行测试,圆满经由过程,又填好一个坑。玩弄了这个Demo一会儿后,总觉得另有些不足,摆布切换页的时刻,头部高低挪动太生硬了。我的想象是在调解头部位置动画的Complate事宜里最先头部的表达式动画,说干咱就干:

var line = _compositor.CreateCubicBezierEasingFunction(new System.Numerics.Vector2(0, 0), new System.Numerics.Vector2(0.6f, 1));var MoveHeaderAnimation = _compositor.CreateScalarKeyFrameAnimation();
MoveHeaderAnimation.InsertExpressionKeyFrame(0f, "_headerVisual.Offset.Y", line);
MoveHeaderAnimation.InsertExpressionKeyFrame(1f, "_manipulationPropertySet.Translation.Y > -100f ? _manipulationPropertySet.Translation.Y: -100f", line);
MoveHeaderAnimation.SetReferenceParameter("_headerVisual", _headerVisual);
MoveHeaderAnimation.SetReferenceParameter("_manipulationPropertySet", _manipulationPropertySet);
MoveHeaderAnimation.DelayTime = TimeSpan.FromSeconds(0.18d);
MoveHeaderAnimation.Duration = TimeSpan.FromSeconds(0.1d);

建立一个关键帧动画,line是缓动结果。关键帧动画ScalarKeyFrameAnimation能够插进去两种帧,一种是InsertKeyFrame(float,float,easingfunctuin),插进去一个数值帧;一种是InsertExpressionKeyFrame(float,string,easingfunctuin),插进去一个表达式帧,二者的第一个参数是进度,最小是0最大是1;第三个参数都是函数,能够设置为线性,贝塞尔曲线函数和步进。

这时候刻就又发明了一个惊!天!大!秘!密!
CompositionAnimation和CompositionAnimationGroup是没有Complated事宜的!
只能手动给延时了。然后...
表达式动画不!支!持!延!时!好为难。

同样是动画,看看隔壁家的StoryBoard,CompositionAnimation你们惭愧不惭愧。

经由一番必应以后,我发明我错怪了他们,CompositionAnimation也能够做到Complated事宜,只是要领有些迂回罢了。

动画完成事宜

经由过程运用关键帧动画,开发人员能够在完成精选动画(或动画组)时运用动画批来举行聚合。 仅能够批处理关键帧动画完成事宜。 表达式动画没有一个确实尽头,因而它们不会激发完成事宜。 假如表达式动画在批中启动,该动画将会像预期那样实行,而且不会影响激发批的时候。

当批内的一切动画都完成时,将激发批完成事宜。 激发批的事宜所需的时候取决于该批中时长最长的动画或耽误最为严峻的动画。 在你须要相识选定的动画组将于什么时候完成以便设计一些其他事情时,聚合完毕状况异常有效。

批在激发完成事宜后开释。 还能够随时挪用 Dispose() 来尽早开释资本。 假如批处理的动画完毕较早,而且你不愿望继承完成事宜,你可能会想要手动开释批对象。 假如动画已中断或作废,将会激发完成事宜,而且该事宜会计入设置它的批。

在动画最先前,新建一个ScopedBatch对象,然后播放动画,紧接着封闭ScopedBatch,动画运转完以后就会触发ScopedBatch的Completed事宜。在ScopedBatch处于运转状况时,会网络一切动画,封闭后最先看管动画的进度。说的云里来雾里去的,照样看代码吧。

var Betch = _compositor.CreateScopedBatch(Windows.UI.Composition.CompositionBatchTypes.Animation);
_headerVisual.StartAnimation("Offset.Y", MoveHeaderAnimation);
Betch.Completed += (s, a) =>{var _headerAnimation = _compositor.CreateExpressionAnimation("_manipulationPropertySet.Translation.Y > -100f ? (_manipulationPropertySet.Translation.Y == 0?This.CurrentValue :_manipulationPropertySet.Translation.Y) : -100f");//_manipulationPropertySet.Translation.Y是ScrollViewer转动的数值,手指向上挪动的时刻,也就是可视部份向下挪动的时刻,Translation.Y是负数。_headerAnimation.SetReferenceParameter("_manipulationPropertySet", _manipulationPropertySet);
    _headerVisual.StartAnimation("Offset.Y", _headerAnimation);
};
Betch.End();

我们把组织和播放_headerAnimation的代码放到了ScopedBatch的Complated事宜里,这时候再运转一下,圆满。

实在照样有点小题目,比方Header没有设置Clip,高低挪动的时刻有时会超越预期的局限之类的,有时候我们会继承议论,这篇已充足长,再长会吓跑人的。
Demo已放到Github,内里用到了一个写的很糙的滑动返回控件,等忙过这段时候整顿下代码就开源,愿望能有大牛指导一二。

Github:

总结一下,完成吸顶最中心的代码就是猎取到ScrollViewer,不一定如果ListView的,邃晓了这一点,一切含有ScrollViewer的控件都能够放到这个这个页面运用。

滑动返回:

以上就是UWP中运用Composition API完成吸顶的引见(二)的细致内容,更多请关注ki4网别的相干文章!

标签:Compositionapi吸顶实现使用


欢迎 发表评论: