アイキャッチ画像

.NET MAUI ShellのTabでiOSでもスワイプで画面遷移する方法

Androidの場合、.NET MAUI ShellのTabは指をスライドさせることで画面遷移することができます。しかし、iOSでは指をスライドさせても画面遷移することができません。

当記事ではiOSでもスワイプして画面遷移する方法を紹介していきます。

紹介環境

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

  • Visual Studio 2022
  • .Net 8
  • Android 14
  • iOS 17.2

Tabについて

Tabは以下のように記載することで上部のタブ表示が行えます。

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="SwipeTabsApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:pages="clr-namespace:SwipeTabsApp.Pages"
    Shell.FlyoutBehavior="Disabled"
    Title="SwipeTabsApp">
    <Tab>
        <ShellContent Title="ページ1" ContentTemplate="{DataTemplate pages:SamplePage1}"/>
        <ShellContent Title="ページ2" ContentTemplate="{DataTemplate pages:SamplePage2}"/>
        <ShellContent Title="ページ3" ContentTemplate="{DataTemplate pages:SamplePage3}"/>
    </Tab>
</Shell>

詳細は以下で紹介しています。良ければ参考にしてみてください。

Androidの動作について

Androidの場合、.NET MAUI ShellのTabは以下のように指をスライドして隣の画面に遷移することができます。

.NET MAUI ShellのTabの動作イメージ(Android)

実装方法

実装方法を説明します。

手順1:ファイルを準備します

以下のようにファイルを準備します。

実装方法のファイル構成

手順2:ハンドラーをカスタムします

Shellのハンドラーをカスタムしていきます。

ShellRendererクラスをカスタムします

ShellのiOSのハンドラーはShellRendererクラスになります。そのShellRendererクラスをカスタムするために継承していきます。実装した内容は以下のようになります。

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

namespace SwipeTabsApp.Platforms.iOS.Renderers.SwipeTab;

public class SwipeTabShellRenderer : ShellRenderer
{
    protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
    {
        return new SwipeTabShellSectionRenderer(this);
    }
}

ShellContentをカスタムするためにCreateShellSectionRendererメソッドを利用していきます。

ShellSectionRendererクラスをカスタムします

CreateShellSectionRendererメソッドで返却しているSwipeTabShellSectionRendererクラスを作成していきます。

using Microsoft.Maui.Controls.Platform.Compatibility;

namespace SwipeTabsApp.Platforms.iOS.Renderers.SwipeTab;

public class SwipeTabShellSectionRenderer : ShellSectionRenderer
{
    public SwipeTabShellSectionRenderer(IShellContext context) : base(context)
    {
    }

    protected override IShellSectionRootRenderer CreateShellSectionRootRenderer(ShellSection shellSection, IShellContext shellContext)
    {
        return new SwipeTabShellSectionRootRenderer(shellSection, shellContext);
    }
}

TabをカスタムするためにCreateShellSectionRootRendererメソッドを利用していきます。

ShellSectionRootRendererクラスをカスタムします

SwipeTabShellSectionRootRendererクラスではスワイプ時のイベントを宣言していきます。

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

namespace SwipeTabsApp.Platforms.iOS.Renderers.SwipeTab;

public class SwipeTabShellSectionRootRenderer : ShellSectionRootRenderer
{
    private SwipeTabShellSectionRootHeader? _swipeTabShellSectionRootHeader;
    private ShellSection _shellSection;

    public SwipeTabShellSectionRootRenderer(ShellSection shellSection, IShellContext shellContext) : base(shellSection, shellContext)
    {
        _shellSection = shellSection;
    }

    protected override IShellSectionRootHeader CreateShellSectionRootHeader(IShellContext shellContext)
    {
        _swipeTabShellSectionRootHeader = new SwipeTabShellSectionRootHeader(shellContext);
        return _swipeTabShellSectionRootHeader;
    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        if (View == null) return;
        if (_shellSection is not Tab) return;
        if (_swipeTabShellSectionRootHeader == null) return;

        // 左にスワイプ時
        UISwipeGestureRecognizer swipeL = new()
        {
            Direction = UISwipeGestureRecognizerDirection.Left
        };
        swipeL.AddTarget(() =>
        {
            // 右の画面に遷移
            _swipeTabShellSectionRootHeader.MoveTab((int)_swipeTabShellSectionRootHeader.SelectedIndex + 1);
        });
        View.AddGestureRecognizer(swipeL);

        // 右にスワイプ時
        UISwipeGestureRecognizer swipeR = new()
        {
            Direction = UISwipeGestureRecognizerDirection.Right
        };
        swipeR.AddTarget(() =>
        {
            // 左の画面に遷移
            _swipeTabShellSectionRootHeader.MoveTab((int)_swipeTabShellSectionRootHeader.SelectedIndex - 1);
        });
        View.AddGestureRecognizer(swipeR);
    }
}

ShellSectionRootHeaderクラスをカスタムします

SwipeTabShellSectionRootHeaderクラスのMoveTabメソッドを用意していきます。MoveTabメソッドでは指定された画面へ遷移できるようにします。

using Microsoft.Maui.Controls.Platform.Compatibility;
using System.Collections.ObjectModel;

namespace SwipeTabsApp.Platforms.iOS.Renderers.SwipeTab;

public class SwipeTabShellSectionRootHeader : ShellSectionRootHeader
{
    public SwipeTabShellSectionRootHeader(IShellContext shellContext) : base(shellContext)
    {
    }

    /// <summary>
    /// 指定された画面へ遷移します。
    /// </summary>
    /// <param name="index"></param>
    public void MoveTab(int index)
    {
        ReadOnlyCollection<ShellContent> shellContents = ((IShellSectionController)ShellSection).GetItems();

        // 指定された画面が存在するか判定します。
        if (index < 0 || shellContents.Count <= index) return;

        // 指定された画面へ遷移します。
        ShellContent shellContent = shellContents[index];
        ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, shellContent);
    }
}

手順3:カスタムしたハンドラーを登録します

カスタムしたハンドラー(SwipeTabShellRenderer)を登録するために、MauiProgramクラスに以下のように実装していきます。

using Microsoft.Extensions.Logging;

#if IOS
using SwipeTabsApp.Platforms.iOS.Renderers.SwipeTab;
#endif

namespace SwipeTabsApp;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
        /* 追加します。======== */
            .ConfigureMauiHandlers((handlers) =>
            {
#if IOS
                handlers.AddHandler(typeof(Shell), typeof(SwipeTabShellRenderer));
#endif
            });
        /* ==================== */

#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }
}

動作イメージ

動作イメージは以下のようになります。

実装時の動作イメージ(iOS)

おわりに

iOSでも.NET MAUI ShellのTabでスワイプすることで画面遷移する方法を紹介してきました。Androidでは最初からできていますが、iOSではできなかったので実装方法を考えてみました。当記事の内容が役に立てば幸いです。