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