前言

MAUI Blazor中,安卓项目的返回键体验很不好,只能如同浏览器一样返回上一页。但很多时候,我们想让他返回的上一页,不一定就是实际上的上一页。而且也想让返回键去支持一些事件,按下返回键触发,例如关闭弹窗。Blazor中有NavigationManager,平时页面的跳转都是靠注入它,调用它的NavigateTo()方法。我们可以写个NavigateService类把他包装起来,再写个方法对安卓返回键做一些专门的处理,放在安卓返回键的处理事件中调用。

正文

添加所需代码

  1. 添加一个接口INavigateService
public interface INavigateService
{
/// <summary>
/// 存储想要返回时触发的方法
/// </summary>
event Action Action;
NavigationManager Navigation { get;protected set; }
/// <summary>
/// 存储URL历史记录
/// </summary>
List<string> HistoryUrl { get; protected set; }
/// <summary>
/// 初始化
/// </summary>
/// <param name="navigation"></param>
void Initialize(NavigationManager navigation);
/// <summary>
/// 导航
/// </summary>
/// <param name="url"></param>
void NavigateTo(string url);
/// <summary>
/// 返回上一页
/// </summary>
void NavigateToBack();
/// <summary>
/// 返回键处理
/// </summary>
/// <returns>true已处理事件,false为无事件可处理(便于做进一步处理,例如退出应用)</returns>
bool OnBackButtonPressed();
}
  1. 添加实现类NavigateService
public class NavigateService : INavigateService
{
public NavigationManager Navigation { get; set; } = default!; public event Action? Action; public void Initialize(NavigationManager navigation)
{
Navigation = navigation;
} public List<string> HistoryUrl { get; set; } = new List<string>(); public void NavigateTo(string url)
{
var href = Navigation.ToBaseRelativePath(Navigation.Uri);
HistoryUrl.Add(href);
Navigation.NavigateTo(url);
}
public void NavigateToBack()
{
string href = string.Empty;
if (HistoryUrl.Count > 0)
{
href = HistoryUrl.Last();
}
Navigation.NavigateTo(href);
if (HistoryUrl.Count > 0)
{
HistoryUrl.RemoveAt(HistoryUrl.Count - 1);
}
} public bool OnBackButtonPressed()
{
if (Action != null && Action?.GetInvocationList().Length > 0)
{
var delegates = Action!.GetInvocationList();
(delegates.Last() as Action)!.Invoke();
return true;
} if (HistoryUrl.Count > 0)
{
NavigateToBack();
return true;
} return false;
}
}
  1. 添加安卓返回键处理类,放在Platforms/Android下,别忘记更改命名空间
using Android.OS;
using Android.Views;
using Android.Widget;
using SwashbucklerDiary.IServices;
using Application = Android.App.Application; namespace XXX.Platforms.Android
{
public static class BackButtonPressed
{
private static byte BackPressCounter; public static bool OnBackButtonPressed(KeyEvent e)
{
if (e.KeyCode == Keycode.Back)
{
if (e.Action == KeyEventActions.Down)
{
var service = MauiApplication.Current.Services.GetRequiredService<INavigateService>();
bool flag = service!.OnBackButtonPressed();
if (!flag)
{
QuitApp();
}
}
return true;
}
return false;
} public static void QuitApp()
{
if (BackPressCounter == 1)
{
Process.KillProcess(Process.MyPid());
}
else if (BackPressCounter == 0)
{
BackPressCounter++;
Toast.MakeText(Application.Context, "再按一次退出", ToastLength.Long)!.Show();
Task.Run(async () =>
{
await Task.Delay(2000);
BackPressCounter = 0;
});
}
}
}
}

4.修改Platforms/Android/MainActivity.cs,添加以下代码

public override bool DispatchKeyEvent(KeyEvent e)
{
var flag = BackButtonPressed.OnBackButtonPressed(e);
if (flag)
{
return true;
} return base.DispatchKeyEvent(e);
}

5.Shared下添加MainLayout.razor.cs

public partial class MainLayout
{
[Inject]
NavigationManager Navigation { get; set; } = default!;
[Inject]
INavigateService NavigateService { get; set; } = default!; protected override void OnInitialized()
{
NavigateService.Initialize(Navigation);
base.OnInitialized();
}
}

6.修改MauiProgram.cs,添加以下代码

builder.Services.AddSingleton<INavigateService, NavigateService>();

如何使用

注入INavigateService

[Inject]
protected INavigateService NavigateService { get; set; } = default!;

如果想要将跳转后的上一页保存到返回服务中,跳转页面时使用NavigateService.NavigateTo(url),当你主动调用NavigateService.NavigateToBack()或者按下安卓返回键时,会跳转回之前保存的上一页。如果想要让返回键执行什么方法,就加入到委托中NavigateService.Action += 你的方法;别忘了在执行后和组件Dispose中把你的方法移出委托NavigateService.Action -= 你的方法;

一些想法

说一下为什么没有继承NavigationManager或者在NavigateService 的构造方法中注入它,NavigationManager这个类比较特殊,也没太玩明白。无论是继承还是构造方法中注入它,得到的都是没有经过初始化的NavigationManager,可以理解为空的,后续也没有办法使用。所以最后选择在MainLayout.razor.cs中注入的NavigationManager,把它存起来。我觉得这么写肯定是不够好,只是没有更好的办法。

后记

本人才疏学浅,也没怎么认真写过文章,所以文章中可能会存在纰漏,也欢迎各位大佬指出。

MAUI Blazor项目中如何添加一个返回服务,并支持安卓返回键的更多相关文章

  1. 在Qt项目中如何添加一个已有的项目作为子项目

    新建一个子目录项目(具体方法参见<类似Visual Studio一样,使用Qt Creator管理多个项目,创建子项目>),然后需要添加的项目移动到该子目录项目目录下,再在其pro文件中添 ...

  2. RK平台Android4.4 添加一个新的遥控器支持以及添加特殊按键【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/52904063 版权声明:本文为博主原创文章,未经博主允许不得转载. 瑞芯微平台 ...

  3. spring项目中如何添加定时器以及在定时器中自动生成sprng注入对象

    最近做了一个java的项目,部门领导给了一套代码让我尽快掌握,说心里话本人真心不喜欢java的这种项目方式,各种配置各种xml文件简直头都大了,下面就将我遇到的其中一个我认为是坑的地方整理出来,希望能 ...

  4. Spring Cloud项目中通过Feign进行内部服务调用发生401\407错误无返回信息的问题

    问题描述 最近在使用Spring Cloud改造现有服务的工作中,在内部服务的调用方式上选择了Feign组件,由于服务与服务之间有权限控制,发现通过Feign来进行调用时如果发生了401.407错误时 ...

  5. 在类库或winform项目中打开另一个winform项目的窗体

    假设类库或winform项目为A,另一个winform项目为B.那麽在A中添加一个接口,里面有一个Show方法,然后在B中写一个类b继承这个接口,并重写这个方法,具体内容为弹出某个窗体.然后在A中另一 ...

  6. 在项目中全局添加FastClick导致图片上传插件在ios端失效的解决方案

    ---恢复内容开始--- 项目是移动端的项目,为了解决300ms的click延迟,所以在全局中加入了FastClick,引入的方式很简单,网上一大堆教程,这里不做赘述 我们就谈,我遇到的问题: 某天产 ...

  7. 在vue项目中如何添加eslint

    随着vue的越做越好,更多的开发者选择使用vue,本篇记录如何在vue项目中添加eslint. 首先第一种就是在vue项目创建初始时就选择了创建,随着初始化一起代入到了项目当中,那么要是一开始觉得es ...

  8. Xcode7.2中如何添加一个Empty Application模板

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) Xcode 6.0正式版之后已经没有所谓的Empty Appl ...

  9. WPF 添加 Resources Dictionary 资源 一般类库项目中无法添加资源文件(ResourceDictionary)

    在文件夹或者项目右键-> Add(添加),会弹出可以快捷添加的资源,但是你会发现没有 ResourceDictionary资源可以选择. 解决此问题方法: 第一步:工程->右键->U ...

  10. Laravel 项目中编写第一个 Vue 组件

    和 CSS 框架一样,Laravel 不强制你使用什么 JavaScript 客户端框架,但是开箱对 Vue.js 提供了良好的支持,如果你更熟悉 React 的话,也可以将默认的脚手架代码替换成 R ...

随机推荐

  1. NC23054 华华开始学信息学

    题目链接 题目 题目描述 因为上次在月月面前丢人了,所以华华决定开始学信息学.十分钟后,他就开始学树状数组了.这是一道树状数组的入门题: 给定一个长度为 \(N\) 的序列 \(A\) ,所有元素初值 ...

  2. NC20279 [SCOI2010]序列操作

    题目链接 题目 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成 ...

  3. FreeSWITCH对接vosk实现实时语音识别

    环境:CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 Python版本:3.9.2 一.背景描述 vosk是一个开源语音识别工具,可识别中文,之前介绍过python使用vosk ...

  4. 安卓机上 4G 内存跑 alpaca,欢迎试用轻量级 LLM 模型推理框架 InferLLM

    从 LLM 火爆以来,社区已经出现了非常多优秀的模型,当然他们最大的特点就是体积大,最近为了让大模型可以在更低端的设备上运行,社区做了非常多的工作, gptq 实现了将模型进行低比特量化,因此降低了运 ...

  5. 联想win8改win7

    知识点分析:目前联想出厂预装Windows 8的台式和一体机使用都是UEFI+GPT硬盘的组合,并且开启了安全启动,但是目前除Window 8以外的其他Windows系统均不支持这种模式,因此如果需要 ...

  6. 第一个c语言项目

    怎么写代码呢 工具:编译器 市面上编译器主要有:clang,gcc,win-tc,msvc,turbo c等 怎么写呢 1.创建一个项目(项目名字不能以中文文字命名) 2.创建一个文件(项目名字不能以 ...

  7. pytest插件开发

    插件的加载方式 外部插件: pip install 安装的插件 本地插件: pytest 自动模块发现机制(conftest.py存放) 内置插件: 代码内部的_pytest目录加载 什么是hook ...

  8. Spring AOP 分享

    初级篇 AOP是什么? Aspect-oriented Programming (AOP) 即面向切面编程.简单来说,AOP 是一种编程范式,允许我们模块化地定义横跨多个对象的行为.AOP 可以帮助我 ...

  9. 2022-08-07:以下go语言代码输出什么?A:1 1;B:3 1;C:0 3;D:不能编译。 package main import ( “fmt“ “math“ ) func main

    2022-08-07:以下go语言代码输出什么?A:1 1:B:3 1:C:0 3:D:不能编译. package main import ( "fmt" "math&q ...

  10. 2021-11-19:[0,4,7] : 0表示这里石头没有颜色,如果变红代价是4,如果变蓝代价是7,[1,X,X] : 1表示这里石头已经是红,而且不能改颜色,所以后两个数X无意义,[2,X,X]

    2021-11-19:[0,4,7] : 0表示这里石头没有颜色,如果变红代价是4,如果变蓝代价是7,[1,X,X] : 1表示这里石头已经是红,而且不能改颜色,所以后两个数X无意义,[2,X,X] ...