supported - navigation xamarin forms
Xamarin Forms NavegaciĆ³n sin animaciĆ³n (4)
Actualmente, la navegación de Xamarin Forms es muy espartana y dudo que haya una buena manera de lograrlo. Además de hacer y "Pop" extra cuando sea necesario.
Tengo una aplicación donde quiero mostrar la página A, desde la que el usuario puede navegar a la página B o C, desde B a A o a C, y desde C solo a A, incluso si el usuario pasa por B para obtener a C
Actualmente, cuando estoy ejecutando la transición B-> C, primero PopAsync
para volver a A y luego hago PushAsync
para llegar a C, de modo que el ''
La pregunta es: ¿existe una forma civilizada de configurar este esquema de navegación sin dejar de depender de la navegación incorporada para realizar un seguimiento de la pila de navegación? No quiero hacer eso yo mismo y usar PushModalAsync
.
Tenga en cuenta que (como se refleja en la imagen) A y C no son los puntos finales de toda la pila de navegación, hay páginas antes de A y después de C, por lo que la pila debe conservarse.
Aquí hay una colección de fragmentos que mezclé junto con algunas otras sutilezas para mejorar NaviagationPage para iOS. Enlace para comentar y codificar en los foros de xamarin.
En iOS, NavigationRenderer
tiene los métodos virtuales OnPopViewAsync
y OnPushAsync
(similar en 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);
}
Llaman al método base correspondiente con dos argumentos, la página y si desean animar la transición. Por lo tanto, es posible que pueda habilitar o deshabilitar la animación con el siguiente enfoque:
- Derive una página de navegación personalizada.
- Agregue una propiedad "Animada".
- Derive un renderizador de navegación personalizado para su página de navegación personalizada.
- Anule los métodos pop y push llamando a sus métodos base con la propiedad "Animated".
Tenga en cuenta que aún no he probado este enfoque, ya que es bastante trabajo por hacer. Pero la desactivación de animaciones en todas las páginas de navegación funcionó de esta manera.
Editar: Me tomó varias horas implementar realmente mi solución para mi propio proyecto. Por lo tanto, compartiré algunos más detalles. (Desarrollé y probé en Xamarin.Forms 1.2.3-pre4.)
La página de navegación personalizada
Además de la propiedad Animated
mencionada anteriormente, mi página de navegación implementa de nuevo las dos funciones de transición y agrega un argumento opcional animated
, que es true
de manera predeterminada. De esta manera, podremos mantener todos los códigos existentes y solo agregar un false
cuando sea necesario.
Además, ambos métodos dormirán durante un tiempo muy corto (10 ms) después de presionar / abrir la página. Sin este retraso, tuvimos problemas con llamadas consecutivas.
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;
}
}
El renderizador de navegación personalizada
El procesador de mi página de navegación personalizada anula ambos métodos de transición y pasa la propiedad Animated
a sus métodos base. (Es feo inyectar una bandera de esta manera, pero no pude encontrar una mejor solución).
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);
}
}
Esto es para iOS. Pero en Android es casi idéntico.
Una aplicación de ejemplo
Para demostrar las posibilidades de presionar consecutivamente y hacer estallar páginas, escribí la siguiente aplicación.
La clase de la App
simplemente crea una nueva página de DemoPage
en CustomNavigationPage
. Tenga en cuenta que esta instancia debe ser públicamente accesible para este ejemplo.
public static class App
{
public static CustomNavigationPage NavigationPage;
public static Page GetMainPage()
{
return NavigationPage = new CustomNavigationPage(new DemoPage("Root"));
}
}
La página de demostración contiene una serie de botones que empujan y abren páginas en diferentes órdenes. Puede agregar o eliminar la opción false
para cada llamada a PushAsync
o 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();
}),
},
},
};
}
}
Sugerencia importante: me costó horas de depuración descubrir que necesita utilizar una instancia de NavigationPage
(o una derivada) en lugar de la Navigation
ContentPage
. De lo contrario, la llamada inmediata de dos o más pops o push provoca un comportamiento extraño y cuelga.
Lo que haría si estuviera haciendo esto es presionar Page C en su NavigationStack y luego sacar la página B de la pila. De esa manera, cuando salgas de la página C, irás a la página 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] );
Alternativamente, cuando incluso salgas de la página C, puedes eliminar todas las instancias del tipo página B de la pila y luego volver atrás 1. En ese caso, la página B permanecería en la pila hasta que estuvieras a punto de retroceder desde la página C a la página A.