アイキャッチ画像

.Net MAUI ShellでiOSのスワイプバックを無効にする方法について

.Net MAUI Shellは、Shell.OnBackButtonPressedでAndroidのバックボタンを無効にできます。しかし、iOSのスワイプバックは無効にできません。

当記事は、iOSのスワイプバックを無効にする方法を紹介していきます。

紹介環境

当記事は以下の環境で作成しています。

開発環境

  • Visual Studio 2022
  • .Net 8

iOSでスワイプバックを無効にする方法

iOSのスワイプバックは、UINavigationController.InteractivePopGestureRecognizer.Enabled(true:有効、false:無効)で制御できます。

以下の手順でUINavigationController.InteractivePopGestureRecognizer.Enabledを利用して、スワイプバックを無効にしていきます。

手順1:ShellSectionRendererをカスタマイズします

UINavigationController.InteractivePopGestureRecognizer.Enabledの制御は、ShellSectionRendererをカスタマイズして行います。

カスタマイズしたShellSectionRendererは、以下のようになります。

using Microsoft.Maui.Controls.Platform.Compatibility;

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp.Platforms.iOS.Handlers;

public class CustomShellSectionRenderer : ShellSectionRenderer
{
    private Page? _displayedPage;

    public CustomShellSectionRenderer(IShellContext context) : base(context)
    {
    }

    protected override void OnDisplayedPageChanged(Page page)
    {
        base.OnDisplayedPageChanged(page);

        // 遷移時に適用します。
        if (_displayedPage == page) return;
        _displayedPage = page;
        if (_displayedPage != null)
        {
            UpdateIsEnabledBackGesture();
        }
    }

    private void UpdateIsEnabledBackGesture()
    {
        // スワイプバックを無効にします。
        InteractivePopGestureRecognizer.Enabled = false;
    }
}

遷移時に適用する必要がありますので、OnDisplayedPageChangedをオーバーライドしています。

手順2:ShellRendererをカスタマイズします

カスタマイズしたShellSectionRendererは、ShellRendererをカスタマイズして呼び出します。

カスタマイズしたShellRendererは、以下のようになります。

using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.Controls.Platform.Compatibility;

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp.Platforms.iOS.Handlers;

public class CustomShellRenderer : ShellRenderer
{
    protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
    {
        // カスタマイズしたShellSectionRendererを呼び出します。
        return new CustomShellSectionRenderer(this);
    }
}

手順3:カスタマイズしたShellRendererを登録します

カスタマイズしたShellRendererは、アプリに登録する必要があります。

アプリの登録は以下のよう行います。

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            // カスタマイズしたShellRendererを登録します。
            .ConfigureMauiHandlers(handlers =>
            {
#if IOS
                handlers.AddHandler(typeof(AppShell), typeof(Platforms.iOS.Handlers.CustomShellRenderer));
#endif
            });

        return builder.Build();
    }
}

これでiOSのスワイプバックが無効になります。

Androidのバックボタンと一緒に制御する方法

iOSでスワイプバックを無効にする方法を利用して、iOSのスワイプバックとAndroidのバックボタンを制御できる添付プロパティを作成していきます。

手順1:添付プロパティを準備します

iOSのスワイプバックとAndroidのバックボタンを制御するために、添付プロパティ(IsEnabledBackGesture)を以下のように準備します。

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp.CustomController;

public class CustomPage
{
    public static readonly BindableProperty IsEnabledBackGestureProperty =
        BindableProperty.CreateAttached("IsEnabledBackGesture", typeof(bool), typeof(CustomPage), true);

    public static bool GetIsEnabledBackGesture(BindableObject obj) => (bool)obj.GetValue(IsEnabledBackGestureProperty);

    public static void SetIsEnabledBackGesture(BindableObject obj, bool value) => obj.SetValue(IsEnabledBackGestureProperty, value);
}

手順2:iOSのスワイプバックを制御します

iOSのスワイプバックを制御するためにCustomShellSectionRendererを以下のように修正します。

using Microsoft.Maui.Controls.Platform.Compatibility;
using SampleApp.CustomController;

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp.Platforms.iOS.Handlers;

public class CustomShellSectionRenderer : ShellSectionRenderer
{
    private Page? _displayedPage;

    public CustomShellSectionRenderer(IShellContext context) : base(context)
    {
    }

    protected override void OnDisplayedPageChanged(Page page)
    {
        base.OnDisplayedPageChanged(page);

        // 遷移時に適用します。
        if (_displayedPage == page) return;
        _displayedPage = page;
        if (_displayedPage != null)
        {
            UpdateIsEnabledBackGesture();
        }
    }

    private void UpdateIsEnabledBackGesture()
    {
        // スワイプバックを制御します。
        InteractivePopGestureRecognizer.Enabled = CustomPage.GetIsEnabledBackGesture(Shell.Current.CurrentPage);
    }
}

手順3:Androidのバックボタンを制御します

Androidのバックボタンを制御するために、Shell.OnBackButtonPressedを以下のように利用していきます。

using SampleApp.CustomController;

// 名前空間はプロジェクトに合わせてください。
namespace SampleApp;

public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
        Routing.RegisterRoute("SamplePage1", typeof(SamplePage1));
    }

    protected override bool OnBackButtonPressed()
    {
        // バックボタンを制御します。
        if (CustomPage.GetIsEnabledBackGesture(CurrentPage))
        {
            return base.OnBackButtonPressed();
        }
        return true;
    }
}

これでiOSのスワイプバックとAndroidのバックボタンを制御できるようになります。

利用方法してみる

作成したCustomPage.IsEnabledBackGestureは以下のように利用します。例では、iOSのスワイプバックとAndroidのバックボタンを無効にしています。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:control="clr-namespace:SampleApp.CustomController"
    control:CustomPage.IsEnabledBackGesture="False"
    x:Class="SampleApp.SamplePage1"
    Title="SamplePage1">
    <VerticalStackLayout>
        <Label Text="サンプルプログラム" VerticalOptions="Center" HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentPage>

終わりに

Androidのバックボタンは簡単に無効できましたが、iOSのスワイプバックを無効にできなかったので作成してみました。当記事の内容が役に立てば幸いです。