it-swarm.com.de

Wie gehe ich mit Xamarin Forms in die Rückwärtsnavigation ein?

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. 

13
imgen

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. 

14
Kyle

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

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

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.

1
Anshu

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.

1
lauxjpn

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:

  1. 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

  2. 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);
        }           
    }
1
AXE

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

  • Erstellen Sie ein ganzseitiges Popup mit undurchsichtigem Hintergrund
  • Ü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 ????

  • [x] Android
  • [x] iOS
  • [-] Windows Phone (veraltet. Verwenden Sie v1.1.0-pre5, wenn WP benötigt wird)
  • [x] UWP (Mindestziel: 10.0.16299)
0
 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.

0

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
}
0
El0din