maui中安卓端切换标签页
maui中安卓端切换标签页WebView
maui中安卓端切换标签页取消滑动切换,只能点击
在电脑端是点击切换,但是在安卓端 左右滑动也可以切换,能不能取消滑动切换,只能点击
<!-- 第一个标签页:音乐播放器 -->
<ContentPage Title="🎵音乐播放" IconImageSource="🎵">
<!-- 第二个标签页:网页浏览 -->
<ContentPage Title="🌐网页浏览" IconImageSource="🌐">
<Grid>
<WebView x:Name="WebBrowser" Source="https://www.2t58.com/list/djwuqu.html" VerticalOptions="Fill" HorizontalOptions="Fill" />
</Grid>
</ContentPage> 在电脑端是点击切换,但是在安卓端 左右滑动也可以切换,能不能取消滑动切换,只能点击
你这个效果是 .NET MAUI 的 TabbedPage 默认行为:
- 在 Android 上,Tab 切换除了点击 TabBar,还支持 左右滑动手势切换。
- 在 Windows / 桌面端,默认只支持点击。
如果你只想保留 点击切换,需要禁用 ViewPager 的滑动手势。MAUI 里目前没有直接的 XAML 属性能关掉,只能通过 平台定制(Handler / CustomRenderer) 来实现。
✅ 解决方案(禁止 Android 左右滑动切换)
创建一个 自定义 Handler 来禁用 ViewPager2 的滑动:
1. 新建一个类(例如 NoSwipeTabbedPage)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MauiApp1.Controls
{
public class NoSwipeTabbedPage : TabbedPage
{
}
}
2. 在 Platforms/Android 下加 Handler 映射
using Android.Views;
using AndroidX.RecyclerView.Widget;
using AndroidX.ViewPager2.Widget;
using Microsoft.Maui.Handlers;
using View = Android.Views.View;
namespace MauiApp1.Platforms.Android
{
public class NoSwipeTabbedPageHandler : TabbedViewHandler
{
public NoSwipeTabbedPageHandler() : base(Mapper)
{
}
public static new PropertyMapper<TabbedPage, TabbedViewHandler> Mapper =
new PropertyMapper<TabbedPage, TabbedViewHandler>(TabbedViewHandler.Mapper)
{
[nameof(TabbedPage.CurrentPage)] = MapCurrentPage
};
private static void MapCurrentPage(TabbedViewHandler handler, TabbedPage page)
{
//// 调用默认实现
//if (TabbedViewHandler.Mapper.TryGetValue(nameof(TabbedPage.CurrentPage), out var map))
//{
// map.Invoke(handler, page);
//}
// 然后禁止滑动
if (handler.PlatformView is ViewPager2 viewPager)
{
if (viewPager.GetChildAt(0) is RecyclerView recyclerView)
{
recyclerView.SetOnTouchListener(new BlockSwipeTouchListener());
}
}
}
private class BlockSwipeTouchListener : Java.Lang.Object, View.IOnTouchListener
{
public bool OnTouch(View? v, MotionEvent? e)
{
return true; // 始终消费事件,禁止滑动
}
}
}
}
3. 在 MauiProgram.cs 里注册 Handler
using YourApp.Controls;
using YourApp.Platforms.Android;
builder.ConfigureMauiHandlers(handlers =>
{
#if ANDROID
handlers.AddHandler(typeof(NoSwipeTabbedPage), typeof(NoSwipeTabbedPageHandler));
#endif
});
4. 使用方式
把你的页面 TabbedPage 换成 NoSwipeTabbedPage:
<?xml version="1.0" encoding="utf-8" ?>
<controls:NoSwipeTabbedPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:MauiApp1.Controls"
x:Class="YourApp.MainPage">
<!-- 第一个标签页 -->
<ContentPage Title="🎵音乐播放" IconImageSource="🎵">
...
</ContentPage>
<!-- 第二个标签页 -->
<ContentPage Title="🌐网页浏览" IconImageSource="🌐">
<Grid>
<WebView x:Name="WebBrowser"
Source="https://www.2t58.com/list/djwuqu.html"
VerticalOptions="Fill"
HorizontalOptions="Fill"/>
</Grid>
</ContentPage>
</controls:NoSwipeTabbedPage>
这样在 Android 上就不能左右滑动切换,只能点击 Tab 切换; 在 Windows / iOS 上不受影响。
要不要我帮你再给出一个 iOS 禁用滑动的写法(虽然 iOS 默认没左右滑动切换)
没有<controls:选项 🔑 关键点
xmlns:controls="clr-namespace:MauiApp1.Controls"必须对应你 C# 文件里定义的命名空间。如果你的项目不叫
MauiApp1,或者NoSwipeTabbedPage.cs在别的命名空间下,就要改成实际的命名空间。如果
NoSwipeTabbedPage在 单独的类库 里,还需要加;assembly=库名,例如:xmlns:controls="clr-namespace:MyLib.Controls;assembly=MyLib"
改成了 <controls:NoSwipeTabbedPage> 之后,XAML 报错提示这些属性(BackgroundColor、BarBackgroundColor、SelectedTabColor、UnselectedTabColor)在 MainPage 上不存在。
你在 XAML 顶部写了
x:Class="MauiApp1.MainPage"
这会让编译器认为 MainPage.xaml 对应的 C# 后置类是 MauiApp1.MainPage : NoSwipeTabbedPage,但是它仍然用 MainPage 来做类型检查,导致找不到 TabbedPage 的属性。
✅ 两种解决方案
方案一:把 MainPage 继承自 NoSwipeTabbedPage
打开 MainPage.xaml.cs,把它的基类从 ContentPage 改为 NoSwipeTabbedPage:
public partial class MainPage : NoSwipeTabbedPage
这样,MainPage 本身就是一个 NoSwipeTabbedPage,XAML 里的属性(BackgroundColor、BarBackgroundColor 等)就能识别了。
方案二:不修改 MainPage,直接把 NoSwipeTabbedPage 用作 Shell 的页面
如果你想保留 MainPage : ContentPage,也可以新建一个 TabbedHostPage.xaml:
<controls:NoSwipeTabbedPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:MauiApp1.Controls"
x:Class="MauiApp1.TabbedHostPage"
BackgroundColor="#F5F5F5"
BarBackgroundColor="#FFFFFF"
SelectedTabColor="#1DB954"
UnselectedTabColor="#666666">
<ContentPage Title="🎵音乐播放">
<!-- 播放器内容 -->
</ContentPage>
<ContentPage Title="🌐网页浏览">
<WebView Source="https://www.2t58.com/list/djwuqu.html" />
</ContentPage>
</controls:NoSwipeTabbedPage>
然后在 TabbedHostPage.xaml.cs 里继承 NoSwipeTabbedPage:
using MauiApp1.Controls;
namespace MauiApp1;
public partial class TabbedHostPage : NoSwipeTabbedPage
{
public TabbedHostPage()
{
InitializeComponent();
}
}
这样就不会和 MainPage 冲突了。
🔑 总结
- 如果你要把
MainPage就当作NoSwipeTabbedPage→ 修改MainPage.xaml.cs继承自NoSwipeTabbedPage(推荐做法)。 - 如果
MainPage本来只是个普通 ContentPage → 新建一个 TabbedPage 容器页面,不要混用。
在电脑端可以WebView 里面打开子页面,为什么安卓端不可以
<!-- 第一个标签页:音乐播放器 -->
<ContentPage Title="🎵音乐播放" IconImageSource="🎵">
<!-- 第二个标签页:网页浏览 -->
<ContentPage Title="🌐网页浏览" IconImageSource="🌐">
<Grid>
<WebView x:Name="WebBrowser" Source="https://www.2t58.com/list/djwuqu.html" VerticalOptions="Fill" HorizontalOptions="Fill" />
</Grid>
</ContentPage> 在电脑端可以WebView 里面打开子页面,为什么安卓端不可以
用多个页面 试试呢
或者一个页面 全操作结束
通过 NuGet 安装其他插件显示
<controls:NoSwipeTabbedPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="MauiApp1.MainPage"
xmlns:controls="clr-namespace:MauiApp1.Controls"
BackgroundColor="#F5F5F5" > <!-- 第一个标签页:音乐播放器 -->
<!--<ContentPage Title="🎵音乐播放" IconImageSource="🎵">--> <!--</ContentPage>-->
<!-- 第二个标签页:网页浏览 --><!-- 即使没有这个标签 安卓端一直往下滑动后 界面会卡住
<ContentPage Title="🌐网页浏览" IconImageSource="🌐">
<Grid>
// <WebView x:Name="WebBrowser" Source="https://www.2t58.com/list/djwuqu.html" VerticalOptions="Fill" HorizontalOptions="Fill" Navigating="OnWebViewNavigating" />
</Grid>
<!--</controls:NoSwipeTabbedPage>-->
</ContentPage> 检查一下,为什么在安卓端一直往下滑动后 界面会卡住
直接原因就是用了标签页 不能安卓界面使用标签页,界面会卡住 取消改成ContentPage后就不卡了
启动入口:MainPage = new AppShell();
页面组织:用 AppShell.xaml 来放 Tab
页面跳转:用 Shell.Current.GoToAsync(...)