2015-06-05 13 views
5

Próbowałem użyć nawigacji wstecznej przez przesłonięcie OnBackButtonPressed, ale jakoś nie został w ogóle wywołany. Korzystam z wersji ContentPage i najnowszej wersji 1.4.2.Jak obsługiwać/anulować nawigację zwrotną w formularzach Xamarin

+1

Wydaje mi się, że wydarzenie jest przeznaczone specjalnie dla przycisku wstecznego sprzętu Android, a nie dla ogólnych wydarzeń nawigacyjnych "wstecz". – Jason

+0

Wiem. Próbowałem na systemie Android i przycisk powrotu sprzętu, ale nie otrzymałem nazwy – imgen

Odpowiedz

4

porządku, afte Przez wiele godzin to wymyśliłem. Istnieją trzy części tego.

# 1 Obsługa tylnego przycisku sprzętowego na Androidzie. Ta jest łatwa, nadpisz OnBackButtonPressed. Pamiętaj, że jest to tylko dla przycisku powrotu sprzętu i tylko dla Androida. Nie obsłuży przycisku wstecz paska nawigacji. Jak widać, starałem się z powrotem przez przeglądarkę przed wycofania się strony, ale można umieścić cokolwiek logika trzeba w.

protected override bool OnBackButtonPressed() 
    { 
     if (_browser.CanGoBack) 
     { 
      _browser.GoBack(); 
      return true; 
     } 
     else 
     { 
      //await Navigation.PopAsync(true); 
      base.OnBackButtonPressed(); 
      return true; 
     } 
    } 

# 2 iOS nawigacji przycisk Wstecz. Ten był naprawdę trudny, jeśli rozejrzysz się po Internecie, znajdziesz kilka przykładów zastąpienia przycisku wstecz nowym przyciskiem niestandardowym, ale prawie niemożliwe jest sprawienie, by wyglądał jak inne strony. W tym przypadku zrobiłem przezroczysty przycisk, który znajduje się nad normalnym przyciskiem.

[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, jest podchwytliwy.W starszych wersjach i przyszłymi wersjami Form raz rozwiązany, można po prostu zastąpić OnOptionsItemselected jak ten

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

Jednakże, jeśli używasz FormsAppCompatActivity, to trzeba dodać na swojej onCreate w główną działalność to ustawić pasek narzędzi:

Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar); 
      SetSupportActionBar(toolbar); 

Ale czekaj! Jeśli masz zbyt starą wersję .Forms lub zbyt nową wersję, pojawi się błąd, w którym pasek narzędzi ma wartość null. Jeśli tak się stanie, zhakowane razem sposób, w jaki udało mi się to zrobić, aby dotrzymać terminu jest właśnie taki. W OnCreate w 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 jest strona, a androidAction jest Action że biegnę na OnAppearing jeśli Platforma Android jest na mojej stronie. W tym momencie w aplikacji pasek narzędzi przestanie być pusty.

Jeszcze kilka kroków, a rendering na iOS, który stworzyliśmy powyżej, wykorzystuje właściwości, które należy dodać do strony, na której renderujesz renderer. Robiłem to dla mojej klasy MyAdvantagePage, którą stworzyłem, która implementuje ContentPage. Więc w moim MyAdvantagePage klasy I dodaje

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

Teraz, że wszystko jest zrobione, na żadnym z moich MyAdvantagePage mogę dodać tego

: 


this.EnableBackButtonOverride = true; 
      this.CustomBackButtonAction = async() => 
      { 
       if (_browser.CanGoBack) 
       { 
        _browser.GoBack(); 
       } 
       else 
       { 
        await Navigation.PopAsync(true); 
       } 
      }; 

To powinno być wszystko, aby zmusić go do pracy na Android sprzęt z powrotem i nawigacja wstecz dla systemu Android i iOS.

+0

A więc ... okazuje się, że masz TabbedPage i używasz mojego strasznego hacka, aby obejść błąd Xamarin.Forms, że przechwytuje tylko przycisk Wstecz na przycisku wstecz na pierwszej stronie Najwyraźniej tylne przyciski na innych stronach są inne ...? Czy ktoś ma poprawkę dla wszystkich kart? – Kyle

+0

wydaje się nie działać na stronie MasterDetail ... – Alex

10

Masz rację, w swojej klasie strony zastąpić OnBackButtonPressed i wrócić true, jeśli chcesz zapobiec nawigacji. Działa to dobrze dla mnie i mam tę samą wersję.

protected override bool OnBackButtonPressed() 
{ 
    if (Condition) 
     return true; 
    return base.OnBackButtonPressed(); 
} 
+2

Wygląda na to, że w Xamarin Forms jest błąd, który mówi, że jeśli użyję TabbedPage jako strony głównej, to OnBackButtonPressed nie zostanie wywołany. Powiedziano mi, że facet wydaje się pochodzić z Xamarin – imgen

+0

Jak uzyskać stronę, do której prowadzi nawigacja? –

+2

[Dokumenty] (https://developer.xamarin.com/api/member/Xamarin.Forms.NavigationPage.OnBackButtonPressed() /) mówią "To zdarzenie nie jest wywoływane w systemie iOS". –

1

W zależności od tego, co dokładnie szukasz (nie polecam za pomocą tego, czy chcesz po prostu zrezygnować z powrotem przycisk nawigacyjny), OnDisappearing może być inna opcja:

protected override void OnDisappearing() 
{ 
     //back button logic here 
} 
+4

Kiedy próbowałem przez zastąpienie OnDisappear są dwa problemy: 1. Strona już zniknęła, więc "Czy jesteś pewien?" pojawi się okno dialogowe na poprzedniej stronie. 2. Nie można anulować działania wstecz. – Amrut

+0

[tutaj] (https://forums.xamarin.com/discussion/21631/is-there-nay-way-cancelling-the-back-button-event-from-the-navigationpage) to rozwiązania specyficzne dla platformy –

+1

Funkcja OnDisappearing jest również wywoływana po zablokowaniu ekranu telefonu lub po przejściu do innej aplikacji. nie tylko przy przejściu do poprzedniej strony – batmaci

0
protected override bool OnBackButtonPressed() 
     { 
      base.OnBackButtonPressed(); 
       return true; 
     } 

base.OnBackButtonPressed() returns false on click of hardware back button. 
In order to prevent operation of back button or prevent navigation to previous page. the overriding function should be returned as true. On return true, it stays on the current xamarin form page and state of page is also maintained. 
1

OnBackButtonPressed() będzie to wywoływane, gdy zostanie naciśnięty przycisk powrotu sprzętu, tak jak w Androidzie. To nie zadziała na przycisku powrotu oprogramowania, jak w ios.

1

Dla każdego, kto wciąż walczy z tym problemem - zasadniczo nie można przechwytywać wstecznej między platformami nawigacyjnymi. Mimo, że istnieją dwa podejścia, które skutecznie rozwiązać problem:

  1. ukryć przycisk NavigationPage z powrotem NavigationPage.ShowHasBackButton(this, false) i popychają stronę modalne, który ma zwyczaj Back/Cancel/przycisk Zamknij

  2. Intercept tył nawigacja natywnie dla każdej platformy. To jest dobry artykuł, który robi to dla iOS i Androida: https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/

Dla UWP jesteś na własną rękę :)

Edit:

Cóż, już nie, ponieważ to zrobiłem :) faktycznie okazało się całkiem proste - jest tylko jeden przycisk z powrotem i jest obsługiwany przez form więc po prostu trzeba zastąpić ContentPage za OnBackButtonPressed:

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); 
     }   
    } 
Powiązane problemy