这里使用了一个ScrollProgressProvider.cs,我们这篇文章先解析一下整体的动画思路,以后再详细解释这个Provider的实现方式。 结构 整个页面大致结构是
这个Header是修改的ListBox,当然也可以用ListView代替。 隐藏Pivot默认Header的方式是在Pivot的样式中找到如下行。 ... 动画过程大致就是在Pivot页面切换时,查找到当页的ScrollViewer,绑定动画。 查找 大家在爬视图树时,应该经常遇到元素还未加载的情况,这里为了解决这种状况,封装了一个WaitForLoaded方法。 private async Task WaitForLoaded(FrameworkElement element, Func func, Predicate pre, CancellationToken cancellationToken) { TaskCompletionSource tcs = null; try { tcs = new TaskCompletionSource(); cancellationToken.ThrowIfCancellationRequested(); var result = func.Invoke(); if (pre(result)) return result; element.Loaded += Element_Loaded; return await tcs.Task; } catch { element.Loaded -= Element_Loaded; var result = func.Invoke(); if (pre(result)) return result; } return default; void Element_Loaded(object sender, RoutedEventArgs e) { if (tcs == null) return; try { cancellationToken.ThrowIfCancellationRequested(); element.Loaded -= Element_Loaded; var _result = func.Invoke(); if (pre(_result)) tcs.SetResult(_result); else tcs.SetCanceled(); } catch { System.Diagnostics.Debug.WriteLine("canceled"); } } } 使用起来是这样的 CancellationTokenSource cts; private async void EventChanged(object sender, EventArgs e) { if (cts != null) cts.Cancel(); cts = new CancellationTokenSource(TimeSpan.FromSeconds(2)); var child = await WaitForLoaded(element, () => find_element_method(), c => judge_find_success_method(), cts.Token); } 我们在Pivot的SelectionChanged事件里,修改ScrollProgressProvider托管的ScrollViewer,provider就会自动将ScrollViewer设置到正确的位置。 接下来在Page的Loaded事件中绑定动画,这里有两种选择。provider提供了ProgressChanged事件和GetProgressPropertySet方法。可以在ProgressChanged事件中直接设置元素的值来实现动画,不过由于ScrollViewer的限制,ProgressChanged事件触发频率不是很高,所以更推荐使用GetProgressPropertySet获取到CompositionPropertySet,通过Composition Api实现动画。 var providerProp = provider.GetProgressPropertySet(); var gv = ElementCompositionPreview.GetElementVisual(Target); // 容器Visual var tv = ElementCompositionPreview.GetElementVisual(HeaderText); //文本Visual ScrollProgressProvider生成的PropertySet内有progress和threshold两个字段可以用作动画。 Composition Api提供了Lerp(start, end, progress)方法,用在此处刚好合适。 我们需要定义容器平移,文本平移和文本缩放三个动画。 容器平移向上移动阈值的高度 var gvOffsetExp = Window.Current.Compositor.CreateExpressionAnimation("Vector3(0f, -provider.threshold * provider.progress, 0f)"); gvOffsetExp.SetReferenceParameter("provider", providerProp); gv.StartAnimation("Offset", gvOffsetExp); 文本平移动画从容器中心平移到左下角 var startOffset = "Vector3((host.Size.X - this.Target.Size.X) / 2, (host.Size.Y - 50 - this.Target.Size.Y) / 2, 1f)"; var endOffset = $"Vector3(0f, provider.threshold, 1f)"; var offsetExp = Window.Current.Compositor.CreateExpressionAnimation($"lerp({startOffset}, {endOffset}, provider.progress)"); offsetExp.SetReferenceParameter("host", gv); offsetExp.SetReferenceParameter("provider", providerProp); tv.StartAnimation("Offset", offsetExp); 文本缩放 var scale = "(50f / this.Target.Size.Y)"; var startScale = "Vector3(1f, 1f, 1f)"; var endScale = $"Vector3({scale}, {scale}, 1f)"; var scaleExp = Window.Current.Compositor.CreateExpressionAnimation($"lerp({startScale}, {endScale}, provider.progress)"); scaleExp.SetReferenceParameter("host", gv); scaleExp.SetReferenceParameter("provider", providerProp); tv.StartAnimation("Scale", scaleExp); GitHub: https://github.com/cnbluefire/ShyHeaderPivot ExpressionAnimation: https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Composition.ExpressionAnimation CompositionAnimation: https://docs.microsoft.com/zh-cn/windows/uwp/composition/composition-animation 我的博客: 超威蓝火https://www.cnblogs.com/blue-fire/p/11376450.html