在iOS上,
NavigationRenderer
有虚拟方法
OnPopViewAsync
和
OnPushAsync
(类似于
Android):
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
return base.OnPopViewAsync(page, animated);
}
protected override Task<bool> OnPushAsync(Page page, bool animated)
{
return base.OnPushAsync(page, animated);
}
他们使用两个参数,页面和是否动画转换,调用相应的基本方法。因此,您可以使用以下方法启用或禁用动画:
1. 派生自定义导航页。
2. 添加“Animated”属性。
3. 为自定义导航页派生自定义导航渲染器。
4. 覆盖弹出和推送方法,并使用“Animated”属性调用它们的基本方法。
请注意,我尚未尝试过此方法,因为需要付出很多工作。但是,使用此方法禁用所有导航页面上的动画确实有效。
编辑:我花了几个小时来实际实现我的解决方案,因此我将分享更多细节。(我在Xamarin.Forms 1.2.3-pre4上开发和测试。)
自定义导航页
除了上述“Animated”属性外,我的导航页重新实现了两个转换函数并添加了一个可选参数“animated”,默认情况下为true。这样,我们将能够保留所有现有代码,并仅在需要时添加false。
此外,两种方法将在推送/弹出页面后短暂休眠(10毫秒)。如果没有此延迟,我们将遇到连续调用的问题。
public class CustomNavigationPage: NavigationPage
{
public bool Animated { get; private set; }
public CustomNavigationPage(Page page) : base(page)
{
}
public async Task PushAsync(Page page, bool animated = true)
{
Animated = animated;
await base.PushAsync(page);
await Task.Run(delegate {
Thread.Sleep(10);
});
}
public async Task<Page> PopAsync(bool animated = true)
{
Animated = animated;
var task = await base.PopAsync();
await Task.Run(delegate {
Thread.Sleep(10);
});
return task;
}
}
自定义导航渲染器
我的自定义导航页面的渲染器覆盖了两个过渡方法,并将Animated
属性传递给它们的基本方法。(这种方式注入标志有点丑陋,但我找不到更好的解决方案。)
public class CustomNavigationRenderer: NavigationRenderer
{
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
return base.OnPopViewAsync(page, (Element as CustomNavigationPage).Animated);
}
protected override Task<bool> OnPushAsync(Page page, bool animated)
{
return base.OnPushAsync(page, (Element as CustomNavigationPage).Animated);
}
}
这是针对iOS的。但在Android上几乎完全相同。
一个示例应用程序
为了演示连续推送和弹出页面的可能性,我编写了以下应用程序。
App
类只是创建了一个包装在CustomNavigationPage
中的新的DemoPage
。请注意,此实例必须公开访问以供本示例使用。
public static class App
{
public static CustomNavigationPage NavigationPage;
public static Page GetMainPage()
{
return NavigationPage = new CustomNavigationPage(new DemoPage("Root"));
}
}
演示页面包含许多按钮,可以按不同顺序推入和弹出页面。您可以为每次调用PushAsync
或PopAsync
添加或删除false
选项。
public class DemoPage: ContentPage
{
public DemoPage(string title)
{
Title = title;
Content = new StackLayout {
Children = {
new Button {
Text = "Push",
Command = new Command(o => App.NavigationPage.PushAsync(new DemoPage("Pushed"))),
},
new Button {
Text = "Pop",
Command = new Command(o => App.NavigationPage.PopAsync()),
},
new Button {
Text = "Push + Pop",
Command = new Command(async o => {
await App.NavigationPage.PushAsync(new DemoPage("Pushed (will pop immediately)"));
await App.NavigationPage.PopAsync();
}),
},
new Button {
Text = "Pop + Push",
Command = new Command(async o => {
await App.NavigationPage.PopAsync(false);
await App.NavigationPage.PushAsync(new DemoPage("Popped and pushed immediately"));
}),
},
new Button {
Text = "Push twice",
Command = new Command(async o => {
await App.NavigationPage.PushAsync(new DemoPage("Pushed (1/2)"), false);
await App.NavigationPage.PushAsync(new DemoPage("Pushed (2/2)"));
}),
},
new Button {
Text = "Pop twice",
Command = new Command(async o => {
await App.NavigationPage.PopAsync(false);
await App.NavigationPage.PopAsync();
}),
},
},
};
}
}
重要提示:我花费了数小时的调试时间才发现您需要使用NavigationPage
(或其派生类),而不是ContentPage
的Navigation
!否则,立即调用两个或更多的弹出或推送将导致奇怪的行为和崩溃。
System.Threading
来获取Thread.Sleep
方法。 - Falko