Xamarin表单导航没有动画

Ste*_*rov 4 xamarin xamarin.forms

我有一个应用程序,我想要显示页面A,用户可以从中导航到页面B或C,从B返回到A或C,从C返回到A,即使用户通过B获取到C. 页面导航

目前,当我执行B-> C转换时,我首先PopAsync回到A,然后我做到PushAsync了C,所以'

问题是:有没有一种文明的方式来设置这个导航方案,同时仍然依靠内置的导航来跟踪导航堆栈 - 我不想自己这样做并使用PushModalAsync.

请注意(如图中所示)A和C不是整个导航堆栈的终点,在A之前和之后都有页面,因此必须保留堆栈.

Fal*_*lko 6

在iOS上NavigationRenderer有虚拟方法OnPopViewAsyncOnPushAsync(类似于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);
}
Run Code Online (Sandbox Code Playgroud)

他们使用两个参数调用相应的基本方法,即页面以及是否为过渡设置动画.因此,您可以使用以下方法启用或禁用动画:

  1. 导出自定义导航页面.
  2. 添加"动画"属性.
  3. 为您的自定义导航页面导出自定义导航渲染器.
  4. 使用"Animated"属性覆盖调用其基本方法的pop和push方法.

请注意,我还没有尝试过这种方法,因为要完成一些工作.但是在所有导航页面上禁用动画确实以这种方式工作.


编辑:我花了几个小时来实际为我自己的项目实现我的解决方案.因此,我将分享更多细节.(我在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)
    {
    }

    // Analysis disable once MethodOverloadWithOptionalParameter
    public async Task PushAsync(Page page, bool animated = true)
    {
        Animated = animated;
        await base.PushAsync(page);
        await Task.Run(delegate {
            Thread.Sleep(10);
        });
    }

    // Analysis disable once MethodOverloadWithOptionalParameter
    public async Task<Page> PopAsync(bool animated = true)
    {
        Animated = animated;
        var task = await base.PopAsync();
        await Task.Run(delegate {
            Thread.Sleep(10);
        });
        return task;
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义导航渲染器

我的自定义导航页面的渲染器会覆盖两种转换方法,并将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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这适用于iOS.但在Android上它几乎完全相同.

示例应用程序

为了演示连续推送和弹出页面的可能性,我编写了以下应用程序.

App类简单地创建一个新的DemoPage包裹成一个CustomNavigationPage.请注意,此示例必须可公开访问此实例.

public static class App
{
    public static CustomNavigationPage NavigationPage;

    public static Page GetMainPage()
    {    
        return NavigationPage = new CustomNavigationPage(new DemoPage("Root"));
    }
}
Run Code Online (Sandbox Code Playgroud)

演示页面包含许多按钮,这些按钮以不同的顺序推送和弹出页面.您可以false为每次调用PushAsync或添加或删除选项PopAsync.

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();
                    }),
                },
            },
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

重要提示:我需要花费数小时的调试时间才能发现你需要使用NavigationPage(或衍生物)的实例而不是ContentPage's Navigation!否则,立即调用两个或多个弹出或推送会导致奇怪的行为和崩溃.


小智 5

@Falko 您现在可以包含一个布尔参数:

 Navigation.PushAsync (new Page2Xaml (), false);
Run Code Online (Sandbox Code Playgroud)

Xamarin 文档