【问题标题】:Override nav bar back button click on Xamarin.Forms覆盖导航栏后退按钮单击 Xamarin.Forms
【发布时间】:2022-01-17 03:54:36
【问题描述】:

我在 xamarin.forms 中有表单,如果有待保存的数据,我想在用户单击导航栏按钮时显示弹出消息。我找到了这个example,但它不适用于 Xamarin.Forms 5.0

知道怎么做吗?

【问题讨论】:

  • 这个问题已经被问了几十次了——发帖前请先搜索一下。 google.com/…
  • 进一步考虑,如果您想防止它们在不保存的情况下导航,您可能希望将页面设置为模式

标签: c# xamarin.forms


【解决方案1】:

我对此做了一个快速测试,你可以参考一下。

首先,我创建一个内容页面并设置 CustomBackButtonActionEnableBackButtonOverride 以添加导航方法:

public partial class TestPage5 : ContentPage
    {public Action CustomBackButtonAction { get; set; }
        public static readonly BindableProperty EnableBackButtonOverrideProperty = BindableProperty.Create(
            nameof(EnableBackButtonOverride),
            typeof(bool),
            typeof(TestPage5),
            false
            );
          public bool EnableBackButtonOverride {

            get { return (bool)GetValue(EnableBackButtonOverrideProperty); }
            set { SetValue(EnableBackButtonOverrideProperty, value); }
        }
        public TestPage5()
        {
            InitializeComponent();
            EnableBackButtonOverride = true;
            CustomBackButtonAction = async () => { var result = await DisplayAlert("Alert", "Are you Sure?", "Yes", "No");
                if (result)
                { await Navigation.PopAsync(true); }     };
        }  
        }

然后在 ios 上创建渲染器,同时在 android 上覆盖 OnOptionsItemSelected:

ios(创建一个新的后退按钮并覆盖):

[assembly:ExportRenderer(typeof(TestPage5),typeof(MyRenderer))]
namespace My_Forms_Test3.iOS
{
    public class MyRenderer:Xamarin.Forms.Platform.iOS.PageRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);
            if (((TestPage5)Element).EnableBackButtonOverride)
            {
                SetButton();
            }
        }

           private void SetButton()
            {
            var backbuttonimg = UIImage.FromBundle("backarrow.png");
            backbuttonimg = backbuttonimg.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
            var backbutton = new UIButton(UIButtonType.Custom)
            { HorizontalAlignment=UIControlContentHorizontalAlignment.Left,
            TitleEdgeInsets=new UIEdgeInsets(11.5f,15f,10f,0f),
            ImageEdgeInsets=new UIEdgeInsets(1f,8f,0f,0f)};
            backbutton.SetTitle("Back", UIControlState.Normal);
            backbutton.SetTitleColor(UIColor.White, UIControlState.Normal);
            backbutton.SetTitleColor(UIColor.LightGray, UIControlState.Highlighted);
            backbutton.Font = UIFont.FromName("HelveticaNeue", (nfloat)17);
            backbutton.SetImage(backbuttonimg, UIControlState.Normal);
            backbutton.SizeToFit();
            backbutton.TouchDown += (sender, e) =>
            {
                if (((TestPage5)Element)?.CustomBackButtonAction != null)
                {
                    ((TestPage5)Element)?.CustomBackButtonAction.Invoke();

                }
            };
            backbutton.Frame = new CoreGraphics.CGRect(0, 0, UIScreen.MainScreen.Bounds.Width / 4,
                NavigationController.NavigationBar.Frame.Height);
            var buttoncontainer = new UIView(new CoreGraphics.CGRect(0, 0, backbutton.Frame.Width, backbutton.Frame.Height));
            buttoncontainer.AddSubview(backbutton);
            var fixspace = new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace)
            { Width = -16f };
            var backbuttonitem = new UIBarButtonItem("", UIBarButtonItemStyle.Plain, null) { CustomView = backbutton };
            NavigationController.TopViewController.NavigationItem.LeftBarButtonItems = new[] { fixspace, backbuttonitem };
        }
    }
    }

安卓:

在主要活动中添加以下内容:

protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
 
            base.OnCreate(savedInstanceState);
 
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
 
            //important to trigger OnOptionItemSelected
            Android.Support.V7.Widget.Toolbar toolbar
             = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);

也在 mainactivity.cs 中:

public override bool OnOptionsItemSelected(IMenuItem item)
        {
            // check if the current item id 
            // is equals to the back button id
            if (item.ItemId == 16908332) // xam forms nav bar back button id
            {
                // retrieve the current xamarin 
                // forms page instance
                var currentpage = (TestPage5)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);
            }
        }
 
        //android Hardware back button event
        public override void OnBackPressed()
        {
            // this is really not necessary, but in Android user has both Nav bar back button 
            // and physical back button, so its safe to cover the both events
 
            var currentpage = (BaseContentPage)Xamarin.Forms.Application.Current.
                MainPage.Navigation.NavigationStack.LastOrDefault();
 
            if (currentpage?.CustomBackButtonAction != null)
            {
                currentpage?.CustomBackButtonAction.Invoke();
            }
            else
            {
                base.OnBackPressed();
            }
        }

【讨论】:

  • SetSupportActionBar 需要 AndroidX.AppCompat.Widget.Toolba 而不是 Android.Support.V7.Widget.Toolbar 对象
【解决方案2】:

这是我写的完整的博客,处理相同,

安卓:

我已经使用NavigationPage Renderer在android中实现了这个功能

Android Implementtion

iOS:

我在 iOS 中使用 Page Renderer 来实现这个功能

public class CustomPageRenderer:PageRenderer
{
    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        if (Element != null && Element is BasePage basePage && basePage.BindingContext != null &&
            basePage.BindingContext is BaseViewModel baseViewModel)
        {
            SetCustomBackButton(baseViewModel);
        }
    }
    private void SetCustomBackButton(BaseViewModel baseViewModel)
    {
        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
            baseViewModel.BackPressedAction?.Invoke(false);
        };
        //var views = NavigationController?.NavigationBar.Subviews;
        NavigationController?.NavigationBar.AddSubview(btn);
    }
}

注意:

请在您的基本视图模型中创建 BackPressedAction 动作以捕获后按事件

【讨论】:

  • Android 代码正在使用基于 Prism 的项目。我目前无法将所有代码迁移到棱柱结构。
  • 嗨,@EloyMillanes,如果您仔细查看代码,您会发现我们使用渲染器时对 prism 没有太多依赖。您只需要根据您的结构更改代码,它也可以正常工作。
猜你喜欢
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多