我尝试通过覆盖OnBackButtonPressed
来使用后退导航,但不知何故它根本没有被调用。我正在使用ContentPage
和最新的1.4.2版本。
答案 0 :(得分:16)
好吧,经过几个小时,我想出了这个。它有三个部分。
#1处理android上的硬件返回按钮。这个很容易,覆盖OnBackButtonPressed。请记住,这仅适用于硬件后退按钮和Android。它不会处理导航栏后退按钮。正如您所看到的,我在退出页面之前尝试通过浏览器进行备份,但您可以放置所需的逻辑。
protected override bool OnBackButtonPressed()
{
if (_browser.CanGoBack)
{
_browser.GoBack();
return true;
}
else
{
//await Navigation.PopAsync(true);
base.OnBackButtonPressed();
return true;
}
}
#2 iOS导航后退按钮。这个非常棘手,如果你环顾网络,你会发现一些用新的自定义按钮替换后退按钮的例子,但几乎不可能让它看起来像你的其他页面。在这种情况下,我制作了一个位于普通按钮顶部的透明按钮。
[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,很棘手。在旧版本和未来版本的Forms中修复后,您可以简单地覆盖OnOptionsItemselected,如此
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);
}
}
但是,如果您使用的是FormsAppCompatActivity,则需要在MainActivity中添加OnCreate来设置工具栏:
Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
但是等等!如果您的.Forms版本太旧或太新版本,则工具栏为空时会出现错误。如果发生这种情况,那么我将其用于制定截止日期的黑客攻击方式是这样的。 OnCreate
中的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是一个Page,而androidAction是我在OnAppearing上运行的Action
,如果我的页面上的平台是Android的话。在您的应用中,此时工具栏将不再为空。
更多步骤,我们上面制作的iOS渲染使用您需要添加到渲染器的任何页面的属性。我正在为我创建的MyAdvantagePage
类创建它,它实现了ContentPage。所以在我的MyAdvantagePage
课程中我添加了
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);
}
}
现在这一切都已完成,在我MyAdvantagePage
的任何一个上我都可以添加
:
this.EnableBackButtonOverride = true;
this.CustomBackButtonAction = async () =>
{
if (_browser.CanGoBack)
{
_browser.GoBack();
}
else
{
await Navigation.PopAsync(true);
}
};
这应该是让它在Android硬件上运行的一切,并为Android和iOS导航。
答案 1 :(得分:12)
您是对的,在您的网页类中覆盖OnBackButtonPressed
,如果您想阻止导航,请返回true
。它适用于我,我有相同的版本。
protected override bool OnBackButtonPressed()
{
if (Condition)
return true;
return base.OnBackButtonPressed();
}
答案 2 :(得分:2)
根据您的确切需求(如果您只想取消后退按钮导航,我建议不要使用此功能),OnDisappearing
可能是另一种选择:
protected override void OnDisappearing()
{
//back button logic here
}
答案 3 :(得分:1)
OnBackButtonPressed()在按下硬件后退按钮时会调用它,就像在android中一样。 这不适用于软件后退按钮,如ios。
答案 4 :(得分:1)
对于仍在与此问题作斗争的人 - 基本上你无法拦截跨平台的导航。说过有两种方法可以有效地解决问题:
使用NavigationPage.ShowHasBackButton(this, false)
隐藏NavigationPage后退按钮并按下具有自定义后退/取消/关闭按钮的模态页面
本地拦截每个平台的后退导航。这篇文章适用于iOS和Android:https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/
对于UWP,你可以自己:)
编辑:
好了,自从我做了以后就不再了:)它实际上变得非常简单 - 只有一个后退按钮,它受到Forms支持,所以你只需要覆盖ContentPage的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);
}
}
答案 5 :(得分:1)
诀窍是实现自己的导航页面,该页面继承自NavigationPage
。它具有相应的事件Pushed
,Popped
和PoppedToRoot
。
示例实现可能如下所示:
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将实现以下界面:
public interface IPageLifetime
{
void OnOpening();
void OnClosed();
}
此界面可以在所有页面的基类中实现,然后将其调用委托给它的视图模型。
导航页面可以像这样创建:
var navigationPage = new PageLifetimeSupportingNavigationPage(new MainPage());
MainPage
将成为显示的根页。
当然,你也可以首先使用NavigationPage
并订阅它的事件而不继承它。
答案 6 :(得分:1)
除Kyle答案外 设置
在您的页面内部
public static Action SetToolbar;
出现您的页面
if (Device.RuntimePlatform == Device.Android)
{
SetToolbar.Invoke();
}
MainActivity
YOURPAGE.SetToolbar = () =>
{
Android.Support.V7.Widget.Toolbar toolbar =
this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
};
答案 7 :(得分:1)
我使用Prism libray,并为处理后退按钮/操作,在页面上扩展了Prism的INavigatedAware
接口,并实现了以下方法:
public void OnNavigatedFrom(INavigationParameters parameters)
{
if (parameters.GetNavigationMode() == NavigationMode.Back)
{
//Your code
}
}
public void OnNavigatedTo(INavigationParameters parameters)
{
}
当用户按下导航栏上的“后退”按钮(Android和iOS)并且当用户按下“硬件后退”按钮(仅适用于Android)时,将引发OnNavigatedFrom方法。
答案 8 :(得分:0)
protected override bool OnBackButtonPressed()
{
base.OnBackButtonPressed();
return true;
}
单击硬件后退按钮时, base.OnBackButtonPressed()
返回false。
为了防止后退按钮操作或阻止导航到上一页。覆盖函数应返回true。返回true时,它将保留在当前的xamarin表单页面上,并且还会保持页面状态。
答案 9 :(得分:0)
也许这可能有用,您需要隐藏“后退”按钮,然后用自己的按钮替换:
ObjectB
然后将它们调用为以下方法:
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;
}
答案 10 :(得分:0)
另一种解决方法是使用Rg.Plugins.Popup,它允许您实现漂亮的弹出窗口。它使用另一个NavigationStack => Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopupStack。这样您的页面就不会被NavigationBar环绕了。
就您而言,我会简单地
使用类似这样的方法在⚠️ParentPage⚠️上覆盖↩️OnBackButtonPress for Android:
protected override bool OnBackButtonPressed()
{
return Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopupStack.Any();
}
由于后退按钮会影响通常的NavigationStack,因此当您的“弹出窗口正在显示”时,只要用户尝试使用它,父项就会弹出。
现在呢? Xaml无论您想要什么,都可以使用所需的所有支票来正确关闭弹出窗口。
?这些目标已解决问题?