Xamarin navigation without animation

I have an application where I want to show page A from which the user can navigate to page B or C, from B to A or C, and from C only to A, even if the user when B to get to C Pages Navigation

Currently when I do a transition B-> C, first PopAsync

to go back to A and then I do PushAsync

to go to C, so '

The question is, is there a civilized way to customize this navigation scheme while still relying on inline navigation to keep track of the navigation stack - I don't want to do that myself and use it PushModalAsync

.

Note that (as shown in the image) A and C are not the endpoints of the entire navigation stack, there are pages before A and after C, so the stack needs to be kept.

+3


source to share


5 answers


IOS NavigationRenderer

has virtual methods OnPopViewAsync

and OnPushAsync

(similar to 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);
}

      

They call the corresponding base method two arguments, a page, and animate the transition. Thus, you can enable or disable animations using the following approach:

  • Display a custom navigation page.
  • Add the property "Animated".
  • Output a custom navigation renderer for your custom navigation page.
  • Override the pop and push methods, naming their base methods with the Animated property.

Note that I have not tried this approach yet as it is a pretty definite job. But disabling animation on all navigation pages did work that way.


Edit: It took me a few hours to actually implement my solution for my own project. Therefore, I will share more details. (I developed and tested on Xamarin.Forms 1.2.3-pre4.)

Custom navigation page

Apart from the above property, Animated

my nav page reimplements the two navigation functions and adds an optional argument Animated

which defaults to true

. This way we can keep all of the existing code and only add false

where needed.

Also, both methods will sleep for a very short time (10ms) after clicking / popping up the page. Without this delay, we had problems with sequential calls.

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;
    }
}

      



Custom navigation rendering

The renderer for my custom navigation page overrides both navigation methods and passes the property to Animated

their base methods. (It's kind of ugly to introduce a flag this way, but I couldn't find a better solution.)

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);
    }
}

      

This is for iOS. But on Android it is almost identical.

Sample application

To demonstrate the capabilities of successive clicking and page appearing, I wrote the following application.

The class App

just creates a new DemoPage

one wrapped in CustomNavigationPage

. Please note that this instance must be publicly available for this example.

public static class App
{
    public static CustomNavigationPage NavigationPage;

    public static Page GetMainPage()
    {    
        return NavigationPage = new CustomNavigationPage(new DemoPage("Root"));
    }
}

      

The demo page contains multiple buttons that click and pop pages in different orders. You can add or remove a parameter false

for each call to PushAsync

or 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();
                    }),
                },
            },
        };
    }
}

      

Important hint: . It took me hours of debugging to find out that you need to use an instance NavigationPage

(or derivative) and not ContentPage

Navigation

! Otherwise, immediately invoking two or more taps or taps results in strange behavior and crashes.

+5


source


@Falko You now have the option to enable a boolean parameter:

 Navigation.PushAsync (new Page2Xaml (), false);

      



Xamarin Documentation

+1


source


Xamarin Forms' navigation system is very spartan at the moment and I doubt there is a good way to achieve it. Besides Doing and additional "Pop" if needed.

0


source


Collected here are the snippets I whipped up along with some other niceties to improve the NaviagationPage for iOS. Link to comment and code on the xamarin forums.

0


source


What I would do if I did this, press the "C" button on your navigation stack, and then pop page B from the stack. This way, when you leave page C, you will go to page A.

// Push the page you want to go to on top of the stack.    
await NavigationPage.PushAsync(new CPage()));

// Remove page B from the stack, so when you want to go back next time 
//you will go to page A.   
Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 2] );

      

Alternatively, when you even leave page C, you can remove all instances of type B from the stack and then discard 1. In this case, page B will remain on the stack until you navigate back from page C to page A.

0


source







All Articles