代码改变世界

Xamarin.Forms 在Prism 下实现导航栏回退按钮点击事件截留的正确姿势

2020-11-04 15:19  Dorisoy  阅读(457)  评论(0编辑  收藏  举报

1.定义一个用于实现菜单管理的容器基类 MenuContainerPage 继承自 ContentPage, IMenuContainerPage

 1 public class MenuContainerPage : ContentPage, IMenuContainerPage
 2 {
 3 
 4         SlideMenuView slideMenu;
 5         public SlideMenuView SlideMenu
 6         {
 7             get
 8             {
 9                 return slideMenu;
10             }
11             set
12             {
13                 if (slideMenu != null)
14                     slideMenu.Parent = null;
15                 slideMenu = value;
16                 if (slideMenu != null)
17                     slideMenu.Parent = this;
18             }
19         }
20 
21         public Action ShowMenuAction { get; set; }
22 
23         public Action HideMenuAction { get; set; }
24 
25         public void ShowMenu ()
26         {
27             if (SlideMenu.IsShown)
28             {
29                 HideMenuAction?.Invoke();
30             }
31             else
32             {
33                 ShowMenuAction?.Invoke();
34             }
35         }
36 
37         public void HideMenu ()
38         {
39             HideMenuAction?.Invoke();
40         }
41 
42 
43         public virtual void OnSoftBackButtonPressed()
44         {
45         }
46         public virtual bool NeedOverrideSoftBackButton { get; set; } = false;
47     }

 

2. 定义一个泛型视图基类BaseContentPage<T> 继承自  MenuContainerPage  其中T派生自 ViewModelBase,该类用于模型绑定上下文, 申明 

OnSoftBackButtonPressed 和 NeedOverrideSoftBackButton 用来接受点击事件和开关
 1     public abstract class BaseContentPage<T> : MenuContainerPage where T : ViewModelBase
 2     {
 3         public T ViewModel => (T)this.BindingContext;
 4         public BaseContentPage()
 5         {
 6             Padding = 0;
 7             this.SlideMenu = new RightSideMasterPage();
 8             BackgroundColor = Color.White;
 9             DeviceDisplay.KeepScreenOn = true;
10         }
11         protected override void OnAppearing()
12         {
13             base.OnAppearing();
14         }
15         protected override void OnDisappearing()
16         {
17             base.OnDisappearing();
18         }
19 
20 
21         public override void OnSoftBackButtonPressed()
22         {
23             var bindingContext = BindingContext as ViewModelBaseCutom;
24             bindingContext?.OnSoftBackButtonPressed();
25         }
26         public override bool NeedOverrideSoftBackButton { get; set; } = false;
27 
28     }

3. 要实现导航栏回退按钮侦听事件,需要自定义 NavigationPageRenderer ,这里我们定义一个 CustomNavigationPageRenderer 实现 Android.Views.View.IOnClickListener 接口

  1  public class CustomNavigationPageRenderer : NavigationPageRenderer, Android.Views.View.IOnClickListener
  2     {
  3 
  4         private static readonly FieldInfo ToolbarFieldInfo;
  5         private bool _disposed;
  6         private Toolbar _toolbar;
  7         static CustomNavigationPageRenderer()
  8         {
  9             ToolbarFieldInfo = typeof(NavigationPageRenderer).GetField("_toolbar", BindingFlags.NonPublic | BindingFlags.Instance);
 10         }
 11         public CustomNavigationPageRenderer(Context context) : base(context) { }
 12 
 13         public override void OnViewAdded(Android.Views.View child)
 14         {
 15             base.OnViewAdded(child);
 16 
 17             if (child.GetType() == typeof(Toolbar))
 18             {
 19                 _toolbar = (Toolbar)child;
 20                 _toolbar.ChildViewAdded += Toolbar_ChildViewAdded;
 21             }
 22         }
 23 
 24         private void Toolbar_ChildViewAdded(object sender, ChildViewAddedEventArgs e)
 25         {
 26             var view = e.Child.GetType();
 27             if (view == typeof(AppCompatTextView))
 28             {
 29                 var textView = (AppCompatTextView)e.Child;
 30                 textView.TextSize = 14;
 31                 textView.SetTypeface(null, TypefaceStyle.Bold);
 32                 textView.RequestLayout();
 33                 if (_toolbar != null)
 34                 {
 35                     _toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
 36                 }
 37             }
 38         }
 39 
 40         public new void OnClick(Android.Views.View v)
 41         {
 42             if (!(Element.CurrentPage is MenuContainerPage curPage))
 43             {
 44                 Element.PopAsync();
 45             }
 46             else
 47             {
 48                 if (curPage.NeedOverrideSoftBackButton)
 49                     curPage.OnSoftBackButtonPressed();
 50 
 51                 else Element.PopAsync();
 52             }
 53         }
 54 
 55         protected override void OnLayout(bool changed, int l, int t, int r, int b)
 56         {
 57             base.OnLayout(changed, l, t, r, b);
 58             UpdateToolbarInstance();
 59         }
 60 
 61         protected override void OnConfigurationChanged(Configuration newConfig)
 62         {
 63             base.OnConfigurationChanged(newConfig);
 64             UpdateToolbarInstance();
 65         }
 66 
 67         protected override void Dispose(bool disposing)
 68         {
 69             if (disposing && !_disposed)
 70             {
 71                 _disposed = true;
 72                 RemoveToolbarInstance();
 73             }
 74 
 75             base.Dispose(disposing);
 76         }
 77 
 78         private void UpdateToolbarInstance()
 79         {
 80             RemoveToolbarInstance();
 81             GetToolbarInstance();
 82         }
 83 
 84         private void GetToolbarInstance()
 85         {
 86             try
 87             {
 88                 _toolbar = (Toolbar)ToolbarFieldInfo.GetValue(this);
 89                 _toolbar.SetNavigationOnClickListener(this);
 90             }
 91             catch (Exception exception)
 92             {
 93                 System.Diagnostics.Debug.WriteLine($"Can't get toolbar with error: {exception.Message}");
 94             }
 95         }
 96 
 97         private void RemoveToolbarInstance()
 98         {
 99             if (_toolbar == null) return;
100 
101             _toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
102             _toolbar.SetNavigationOnClickListener(null);
103             _toolbar = null;
104         }
105 
106     }

 其中重写 OnClick(Android.Views.View v)

 1  public new void OnClick(Android.Views.View v)
 2 {
 3             if (!(Element.CurrentPage is MenuContainerPage curPage))
 4             {
 5                 Element.PopAsync();
 6             }
 7             else
 8             {
 9                 if (curPage.NeedOverrideSoftBackButton)
10                     curPage.OnSoftBackButtonPressed();
11 
12                 else Element.PopAsync();
13             }
14         }

 

4. 定义测试页面 SaleOrderBillPage 继承  BaseContentPage<SaleOrderBillPageViewModel>  其中 SaleOrderBillPageViewModel 表示视图模型,在OnAppearing 中 开启当前页面是否启用回退截留

 NeedOverrideSoftBackButton = true;

 1 protected override void OnAppearing()
 2         {
 3             base.OnAppearing();
 4             if (Content == null)
 5             {
 6                 try
 7                 {
 8                     InitializeComponent();
 9 
10                     ToolbarItems.Clear();
11                     NeedOverrideSoftBackButton = true;
12 
13                     string btnIco = "\uf0c7";
14                     foreach (var toolBarItem in this.GetToolBarItems(ViewModel, true, btnIco).ToList())
15                     {
16                         ToolbarItems.Add(toolBarItem);
17                     }
18                 }
19                 catch (Exception ex) { Log.Write(ex); }
20                 return;
21             }
22         }


 

5.  在ViewModelBase 中重写 OnSoftBackButtonPressed

1    public async virtual void OnSoftBackButtonPressed()
2         {
3             var ok = await _dialogService.ShowConfirmAsync("你是否要保存单据?", "提示", "确定", "取消");
4             if (!ok)
5             {
6                 await _navigationService.GoBackAsync();
7             }
8         }

 

当点击返回按钮时,提示表单是否要存储,效果如下:

 

 

 

 

 

 

 

protected override void OnAppearing()        {            base.OnAppearing();            if (Content == null)            {                try                {                    InitializeComponent();
                    ToolbarItems.Clear();                    NeedOverrideSoftBackButton = true;
                    string btnIco = "\uf0c7";                    foreach (var toolBarItem in this.GetToolBarItems(ViewModel, true, btnIco).ToList())                    {                        ToolbarItems.Add(toolBarItem);                    }                }                catch (Exception ex) { Log.Write(ex); }                return;            }        }