Ich habe versucht, die Rückwärtsnavigation zu verwenden, indem ich OnBackButtonPressed
überschreibe, aber irgendwie wurde es überhaupt nicht aufgerufen. Ich verwende die ContentPage
und die neueste Version 1.4.2.
Okay, nach vielen Stunden habe ich das herausgefunden. Es gibt drei Teile.
# 1 Umgang mit der Hardware-Zurück-Taste auf Android. Dies ist einfach, überschreiben Sie OnBackButtonPressed. Denken Sie daran, dass dies nur für einen Hardware-Zurück-Button und nur für Android gilt. Die Schaltfläche "Zurück" der Navigationsleiste wird nicht behandelt. Wie Sie sehen können, habe ich versucht, durch einen Browser zurückzublättern, bevor Sie die Seite verlassen haben. Sie können jedoch die Logik einfügen, die Sie benötigen.
protected override bool OnBackButtonPressed()
{
if (_browser.CanGoBack)
{
_browser.GoBack();
return true;
}
else
{
//await Navigation.PopAsync(true);
base.OnBackButtonPressed();
return true;
}
}
# 2 iOS-Zurücktaste. Dies war wirklich schwierig. Wenn Sie sich im Web umsehen, finden Sie einige Beispiele, wie Sie den Zurück-Button durch einen neuen benutzerdefinierten Button ersetzen. Es ist jedoch fast unmöglich, ihn wie Ihre anderen Seiten zu sehen. In diesem Fall habe ich eine transparente Schaltfläche erstellt, die sich auf der normalen Schaltfläche befindet.
[Assembly: ExportRenderer(typeof(MyAdvantagePage), typeof
(MyAdvantagePageRenderer))]
namespace Advantage.MyAdvantage.MobileApp.iOS.Renderers
{
public class MyAdvantagePageRenderer : Xamarin.Forms.Platform.iOS.PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (((MyAdvantagePage)Element).EnableBackButtonOverride)
{
SetCustomBackButton();
}
}
private void SetCustomBackButton()
{
UIButton btn = new UIButton();
btn.Frame = new CGRect(0, 0, 50, 40);
btn.BackgroundColor = UIColor.Clear;
btn.TouchDown += (sender, e) =>
{
// Whatever your custom back button click handling
if (((MyAdvantagePage)Element)?.
CustomBackButtonAction != null)
{
((MyAdvantagePage)Element)?.
CustomBackButtonAction.Invoke();
}
};
NavigationController.NavigationBar.AddSubview(btn);
}
}
}
Android ist knifflig. In älteren Versionen und zukünftigen Versionen von Forms, die einmal behoben wurden, können Sie das ausgewählte OnOptionsItem einfach überschreiben
public override bool OnOptionsItemSelected(IMenuItem item)
{
// check if the current item id
// is equals to the back button id
if (item.ItemId == 16908332)
{
// retrieve the current xamarin forms page instance
var currentpage = (MyAdvantagePage)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
// check if the page has subscribed to
// the custom back button event
if (currentpage?.CustomBackButtonAction != null)
{
// invoke the Custom back button action
currentpage?.CustomBackButtonAction.Invoke();
// and disable the default back button action
return false;
}
// if its not subscribed then go ahead
// with the default back button action
return base.OnOptionsItemSelected(item);
}
else
{
// since its not the back button
//click, pass the event to the base
return base.OnOptionsItemSelected(item);
}
}
Wenn Sie jedoch FormsAppCompatActivity verwenden, müssen Sie OnCreate in MainActivity Folgendes hinzufügen, um die Symbolleiste festzulegen:
Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
Aber warte! Wenn Sie eine zu alte Version von .Forms oder eine zu neue Version haben, wird ein Fehler angezeigt, bei dem die Symbolleiste null ist. Wenn dies passiert, ist die Art und Weise, wie ich es zusammen gehackt habe, um eine Frist einzuhalten, wie folgt. In OnCreate
in MainActivity
:
MobileApp.Pages.Articles.ArticleDetail.androdAction = () =>
{
Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
};
ArticleDetail ist eine Seite, und androidAction ist eine Action
, die ich unter OnAppearing ausführen kann, wenn die Plattform auf meiner Seite Android ist. Zu diesem Zeitpunkt in Ihrer App ist die Symbolleiste nicht mehr null.
Bei einigen weiteren Schritten werden für das oben erstellte iOS-Rendering Eigenschaften verwendet, die Sie zu der Seite hinzufügen müssen, für die Sie den Renderer erstellen. Ich habe es für meine MyAdvantagePage
-Klasse erstellt, die ich erstellt habe und die ContentPage implementiert. Also habe ich in meiner MyAdvantagePage
-Klasse hinzugefügt
public Action CustomBackButtonAction { get; set; }
public static readonly BindableProperty EnableBackButtonOverrideProperty =
BindableProperty.Create(
nameof(EnableBackButtonOverride),
typeof(bool),
typeof(MyAdvantagePage),
false);
/// <summary>
/// Gets or Sets Custom Back button overriding state
/// </summary>
public bool EnableBackButtonOverride
{
get
{
return (bool)GetValue(EnableBackButtonOverrideProperty);
}
set
{
SetValue(EnableBackButtonOverrideProperty, value);
}
}
Nun, da das alles erledigt ist, kann ich dies auf jeder meiner MyAdvantagePage
hinzufügen
:
this.EnableBackButtonOverride = true;
this.CustomBackButtonAction = async () =>
{
if (_browser.CanGoBack)
{
_browser.GoBack();
}
else
{
await Navigation.PopAsync(true);
}
};
Das sollte alles sein, damit Android-Hardware wieder funktioniert und die Navigation für Android und iOS möglich ist.
Sie haben Recht, in Ihrer Seitenklasse überschreiben Sie OnBackButtonPressed
und geben Sie true
zurück, wenn Sie die Navigation verhindern möchten. Es funktioniert gut für mich und ich habe die gleiche Version.
protected override bool OnBackButtonPressed()
{
if (Condition)
return true;
return base.OnBackButtonPressed();
}
Abhängig davon, wonach Sie genau suchen (ich würde dies nicht empfehlen, wenn Sie einfach die Zurück-Button-Navigation abbrechen möchten), kann OnDisappearing
eine andere Option sein:
protected override void OnDisappearing()
{
//back button logic here
}
OnBackButtonPressed () wird aufgerufen, wenn wie in Android eine Hardware-Rücktaste gedrückt wird. Dies funktioniert nicht beim Drücken der Software-Rücktaste wie in ios.
Der Trick besteht darin, eine eigene Navigationsseite zu implementieren, die von NavigationPage
erbt. Es hat die entsprechenden Ereignisse Pushed
, Popped
und PoppedToRoot
.
Eine Beispielimplementierung könnte folgendermaßen aussehen:
public class PageLifetimeSupportingNavigationPage : NavigationPage
{
public PageLifetimeSupportingNavigationPage(Page content)
: base(content)
{
Init();
}
private void Init()
{
Pushed += (sender, e) => OpenPage(e.Page);
Popped += (sender, e) => ClosePage(e.Page);
PoppedToRoot += (sender, e) =>
{
var args = e as PoppedToRootEventArgs;
if (args == null)
return;
foreach (var page in args.PoppedPages.Reverse())
ClosePage(page);
};
}
private static void OpenPage(Page page)
{
if (page is IPageLifetime navpage)
navpage.OnOpening();
}
private static void ClosePage(Page page)
{
if (page is IPageLifetime navpage)
navpage.OnClosed();
page.BindingContext = null;
}
}
Pages würde die folgende Schnittstelle implementieren:
public interface IPageLifetime
{
void OnOpening();
void OnClosed();
}
Diese Schnittstelle kann in einer Basisklasse für alle Seiten implementiert werden und dann ihre Aufrufe an das Ansichtsmodell delegieren.
Die Navigationsseite und könnte so erstellt werden:
var navigationPage = new PageLifetimeSupportingNavigationPage(new MainPage());
MainPage
wäre die Startseite, die angezeigt werden soll.
Natürlich können Sie auch NavigationPage
an erster Stelle verwenden und die Ereignisse abonnieren, ohne davon zu erben.
Für alle, die noch mit diesem Problem kämpfen, können Sie die hintere Navigation nicht plattformübergreifend abfangen. Allerdings gibt es zwei Ansätze, die das Problem effektiv lösen:
Blenden Sie die NavigationPage-Schaltfläche "Zurück" mit "NavigationPage.ShowHasBackButton(this, false)
" und "Push" auf eine modale Seite aus, die über eine benutzerdefinierte Schaltfläche "Zurück/Abbrechen/Schließen" verfügt
Fangen Sie die Rückennavigation für jede Plattform nativ ab. Dies ist ein guter Artikel, der dies für iOS und Android ermöglicht: https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/
Für UWP bist du alleine :)
Bearbeiten:
Nun, nicht mehr, seit ich es getan habe :) Es stellte sich heraus, dass es ziemlich einfach war - es gibt nur einen Zurück-Button, der von Forms unterstützt wird, also müssen Sie nur OnBackButtonPressed von ContentPage überschreiben:
protected override bool OnBackButtonPressed()
{
if (Device.RuntimePlatform.Equals(Device.UWP))
{
OnClosePageRequested();
return true;
}
else
{
base.OnBackButtonPressed();
return false;
}
}
async void OnClosePageRequested()
{
var tdvm = (TaskDetailsViewModel)BindingContext;
if (tdvm.CanSaveTask())
{
var result = await DisplayAlert("Wait", "You have unsaved changes! Are you sure you want to go back?", "Discard changes", "Cancel");
if (result)
{
tdvm.DiscardChanges();
await Navigation.PopAsync(true);
}
}
else
{
await Navigation.PopAsync(true);
}
}
Eine andere Möglichkeit ist die Verwendung von Rg.Plugins.Popup , mit dem Sie Nice Popup implementieren können. Es wird ein anderer NavigationStack verwendet => Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopupStack. Ihre Seite wird also nicht um die Navigationsleiste gewickelt.
In deinem Fall würde ich einfach
Überschreibe ↩️ OnBackButtonPressed für Android auf ⚠️ParentPage⚠️ mit etwas wie dem Folgenden:
protected override bool OnBackButtonPressed() { return Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopupStack.Any(); }
Da sich die Zurück-Schaltfläche auf den üblichen Navigationsstapel auswirkt, wird Ihr übergeordnetes Element immer dann ausgeblendet, wenn der Benutzer versucht, ihn zu verwenden, während Ihr "Popup" angezeigt wird.
Was jetzt? XAML, was auch immer Sie wollen, um Ihr Popup mit all den Häkchen, die Sie wollen, richtig zu schließen.
???? Problem für diese Ziele gelöst ????
protected override bool OnBackButtonPressed()
{
base.OnBackButtonPressed();
return true;
}
base.OnBackButtonPressed()
gibt beim Klicken der Schaltfläche "Hardware zurück" den Wert "false" zurück. .__ Um die Betätigung der Zurück-Taste oder die Navigation zur vorherigen Seite zu verhindern. Die überschreibende Funktion sollte als wahr zurückgegeben werden. Bei der Rückgabe true bleibt er auf der aktuellen Xamarin-Formularseite und der Seitenstatus wird ebenfalls beibehalten.
Vielleicht kann dies nützlich sein. Sie müssen den Zurück-Button ausblenden und dann durch einen eigenen Button ersetzen:
public static UIViewController AddBackButton(this UIViewController controller, EventHandler ev){
controller.NavigationItem.HidesBackButton = true;
var btn = new UIBarButtonItem(UIImage.FromFile("myIcon.png"), UIBarButtonItemStyle.Plain, ev);
UIBarButtonItem[] items = new[] { btn };
controller.NavigationItem.LeftBarButtonItems = items;
return controller;
}
public static UIViewController DeleteBack(this UIViewController controller)
{
controller.NavigationItem.LeftBarButtonItems = null;
return controller;
}
Rufen Sie dann diese Methoden auf:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.AddBackButton(DoSomething);
UpdateFrames();
}
public override void ViewWillDisappear(Boolean animated)
{
this.DeleteBackButton();
}
public void DoSomething(object sender, EventArgs e)
{
//Do a barrel roll
}