in the previous article we discussed the ceiling operation that does not involve pivot, but in general, the top part is the header of the pivot, so here we will discuss the case of pivot multiple item associated with the same header.
The old look, first make a simple page, the page has a grid when the header, a removed head of the pivot,pivot inside there are three Listview,listview set the page header height consistent with the blank 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> <!--It's too long to be stuck here--></pivot.templ ate><pivot.headertemplate><datatemplate></datatemplate></pivot.headertemplate>< Pivot.itemtemplate><datatemplate><listview itemssource= "{Binding}" ><ListView.Header>< Grid height= "/></listview.header><listview.itemtemplate><datatemplate><textblock" Text= "{Binding}"/></datatemplate></listview. Itemtemplate></listview></datatemplate></pivot.itemtemplate></pivot><grid Height= "Verticalalignment=" "Top" X:name= "_header" ><grid.rowdefinitions><rowdefinition Height= "/>" <rowdefinition height= "/></grid.rowdefinitions><grid" background= "LightBlue" ><TextBlock Fontsize= "" verticalalignment= "center" horizontalalignment= "Center" > I will be hidden </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 template too long is not written here, if necessary, find a system built-in brush resources press F12 to open Generic.xaml, and then search pivot is the other control template can be obtained through this method.
Modify these sentences in the template to remove the head:
<pivotpanel x:name= "Panel" verticalalignment= "Stretch" ><grid x:name= "Pivotlayoutelement" >< Grid.rowdefinitions><rowdefinition height= "0"/><rowdefinition height= "*"/><!--too long do not write--></ Grid.rowdefinitions>
Then is the backstage code, here also will use the previous article Findfirstchild method, here does not post out.
In the same way, the overall _headervisual, preferably in the page of the loaded event to initialize the variables we need, I lazy, and directly into the following Updateanimation method.
Then we write a updateanimation method to update the parameters of the animation when the PivotItem switches.
First Judge if the page is not selected to return, and then get to the current selection of the container, and then the same as the last time to get ScrollViewer, but there is a pit, and later.
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);
}
}
Then update the animation in the pivot's SelectionChanged event:
private void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateAnimation();
}
Point down to run, slide down a bit, and not follow the move. After switching around, it was found that the second time switching to PivotItem can be followed, the next to see the first run to "var _scrollviewer = findfirstchild<scrollviewer> ( SelectionItem); " When the _scrollviewer is null. Think for a long time to realize that the control is not loaded the problem, so that the child control is not taken? Change the word and change it.
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();
};
Run again, and then move on. However, there is a problem that the header will return to its original position once each time it is switched. This is another pit.
Guess when switching PivotItem, _MANIPULATIONPROPERTYSET.TRANSLATION.Y will have an instant to become 0. I stepped on the pit and everyone will stop stepping on it.
Stop the animation before attempting to update the animation.
private void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_headerVisual?.StopAnimation("Offset.Y");
UpdateAnimation();
}
Run, and sure enough it failed.
It takes time for the animation to play when the light flashes. This toggle animation is about five steps:
-
Trigger selectionchanged;
-
The page shifts to the left and fades away;
-
Uninstall the page;
-
Loading new pages;
-
The page moves from the right to the center and appears gradually.
The first step starts before the selectionchanged, then stops the animation, updates the animation, my expression animation all starts to play, his first step also leisurely not to walk the end ...
Simple, in the SelectionChanged Rigayan, you can solve (yes) header homing problem (here again buried a pit):
private async void _pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_headerVisual?.StopAnimation("Offset.Y");await Task.Delay(180);
UpdateAnimation();
}
Run, it's perfect. Then tried it on the phone and almost cried.
For both clicks and touches, the order in which events are triggered and the animation is played is different when you switch pages!
Touch caused by the switch page, is probably the following steps:
-
Sliding causes the page to shift, let go of the page left and gradually disappear
-
Trigger selectionchanged;
-
Uninstall the page;
-
Loading new pages;
-
The page moves from the right to the center and appears gradually.
But after the page disappears, _MANIPULATIONPROPERTYSET.TRANSLATION.Y will become 0! At this time I really collapsed, but in the end I came up with a solution.
_MANIPULATIONPROPERTYSET.TRANSLATION.Y become 0 when the time to ignore him is not good, no more wit. This also does not need selectionchanged write delay, feel their code suddenly become elegant a lot of it.
To modify an expression for _headeranimation:
_headeranimation = _compositor. Createexpressionanimation (
Note: The Max,min,clamp are all functions built into the expression animation, and the relevant information can be seen in the appendix.
Test again, perfect pass, and fill a hole. Play with this demo after a while, always feel that there are some shortcomings, left and right to switch pages, the head up and down moved too stiff. My idea is to start the expression animation of the head in the Complate event that adjusts the animation of the position of the head, and that's what we do:
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);
Create a keyframe animation, line is an easing effect. Keyframe Animation scalarkeyframeanimation can insert two kinds of frames, one is insertkeyframe (Float,float,easingfunctuin), inserting a numeric frame , one is Insertexpressionkeyframe (Float,string,easingfunctuin), insert an expression frame, the first parameter of both is progress, the minimum is 0 maximum is 1, the third parameter is a function, can be set to linear, Bézier curve functions and stepping.
At this time, we found another surprise! Days! Big! Secret! Dense!
Compositionanimation and Compositionanimationgroup are not complated events!
You can only manually give the delay. And then...
Expression Animation No! Support Hold! Yan! When So embarrassing.
The same is the animation, look at the next house storyboard,compositionanimation you ashamed not ashamed.
After some Bing, I found that I wronged them, compositionanimation can also do complated events, but the method is a bit tortuous.
Animation Completion Events
By using Keyframe animations, developers can use animated batches to aggregate when they complete a featured animation (or animation group). Only key-frame animation completion events can be batch-processed. Expression animations do not have an exact end point, so they do not raise completion events. If an expression animation is started in a batch, the animation will execute as expected and will not affect when the batch is raised.
A batch completion event is raised when all animations within a batch are completed. The time required to raise an event for a batch depends on the longest animation in the batch or the most heavily delayed animation. Aggregation end state is useful when you need to know when the selected animation group will be finished to plan some other work.
The batch is released after the completion event is raised. You can also call Dispose () at any time to release resources as early as possible. If the batch animation ends earlier, and you do not want to continue to complete the event, you may want to manually release the batch object. If the animation is interrupted or canceled, a completion event is raised, and the event is counted into the batch that sets it.
Before the animation begins, a new Scopedbatch object is created, then the animation is played, and then the Scopedbatch is turned off, and the Scopedbatch completed event is triggered after the animation finishes running. When Scopedbatch is in the running state, all animations are collected and the progress of the animation is monitored when it is closed. Say the clouds in the fog to go, or look at the code bar.
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();
We put the construction and playback _headeranimation code into the scopedbatch of the Complated event, then run again, perfect.
In fact, there is a small problem, such as the header does not set clip, moving up and down sometimes beyond the expected range of the like, there is time we will continue to discuss, this article is long enough, longer will scare away people.
The demo has been put on GitHub, the use of a very rough written sliding back control, and so busy this time to tidy up the code on the open source, I hope to have Daniel pointing twos.
Github:
Summing up, the implementation of the core of the top of the code is to get to scrollviewer, not necessarily a ListView, understand this, all the controls containing ScrollViewer can be placed on this page to use.
Slide back: