.NET MAUI Shell에 대해

드디어 .NET MAUI의 RC 버전이 나왔습니다.

이전에도 있었는지는 모르겠으나, 적어도 제가 MAUI 발표준비를 했었던 1월까지는 없었던 Shell이라는 개념이 등장하였습니다.
이 Shell은 Xamarin에 익숙한 분들이라면 조금 낯선 개념일텐데 이 기능이 무엇을 하는지에 대해 잠깐 알아봅니다.

이 글은 제가 개인적으로 이해한 것에 따르므로, 잘못된 내용이 있으면 자유롭게 피드백 부탁드립니다.

먼저 Shell은 MSDN에 설명이 자세히 나왔있으나 사실 읽어봐도 개념이 잘 와닿지 않습니다.

하지만 내용을 바탕으로 조금 생각해보면 프로그램의 UI에 해당할 수 있는 가장 안쪽을 Shell이라는 개념을 적용하여 그 위에서 페이지를 자유롭게 이동할 수 있는 것은 아닐까 합니다.

일단 기본적인 구성은 FlyoutItem, TabItem, ShellContent 3가지가 있습니다.
앞의 두 개는 UI 구성 방법을 Flyout 방식이냐 Tab 방식이냐를 나타낼 뿐이고, 이 중 실제 화면에 표현하는 것은 ShellContent입니다.
(TabItemXamarinTabbedPage와 비슷하지만 아래쪽에 나오는 Route 부분과 차이가 있습니다.)

FlyoutItem

<Shell
    x:Class="MyTest.Maui.AppShell"
    ...>

    <FlyoutItem Title="Cats">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" 
                                    Route="CatsPage"/>
       </Tab>
    </FlyoutItem>

</Shell>

TabItem

<Shell
    x:Class="MyTest.Maui.AppShell"
    ...>

    <TabBar>
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:DogsPage}"
                                    Route="DogsPage" />
       </Tab>
    </TabBar>

</Shell>

ShellContent

<Shell
    x:Class="MyTest.Maui.AppShell"
    ...
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="Hello, World!"
        ContentTemplate="{DataTemplate local:MyCustomPage}"
        Route="MyCustomPage" />

</Shell>

코드로 보면 이렇게 생겼는데 가운데 있는 <Tab /> 태그는 생략이 가능합니다.
또한 이를 아래와 같이 섞어서 쓸 수도 있습니다.

<Shell
    x:Class="MyTest.Maui.AppShell"
    ...>

    <FlyoutItem Title="Animals" Route="Animals">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" 
                                    Route="CatsPage"/>
           <ShellContent ContentTemplate="{DataTemplate views:DogsPage}" 
                                    Route="DogsPage"/>
       </Tab>
    </FlyoutItem>

    <ShellContent
        Title="Hello, World!"
        ContentTemplate="{DataTemplate local:MyCustomPage}"
        Route="MyCustomPage" />

</Shell>

여기서 핵심은 Route 키워드입니다.
Route는 루트 페이지를 이동하는 가장 쉬운 방법입니다.

기존 Xamarin에서는 루트 페이지가 아래 코드처럼 고정되어 있어 쉽게 바꿀 수 없었습니다.

// 기존 Xamarin
public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        MainPage = new NavigationPage(new MainPage());
    }
}
// MAUI
public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        MainPage = new AppShell();
    }
}

그러나 여기 Shell을 이용하면 루트 페이지를 굉장히 쉽게 바꿀 수 있습니다.
이때 Route는 그 경로가 되며 이를 Uri 식으로 사용합니다.

예를들어 위 예제에서는 계층도가 아래와 같이 됩니다.

Animals
        CatsPage
        DogsPage
MyCustomPage

이를 Uri로 바꾸면 다음과 같습니다.

//Animals
//Animals/CatsPage
//Animals/DogsPage
//MyCustomPage

각 페이지의 이동은 Uri를 통해 이뤄집니다.
페이지의 이동은 비하인드 코드에서 아래 함수를 이용하면 됩니다.

await (Application.Current.MainView as Shell).Current.GoToAsync("//MyCustomPage");
// 또는
await Shell.Current.GoToAsync("//MyCustomPage");

위에서 사용한 / 기호는 Uri 단위지만 맨 앞에 붙으면 기준점이 달아지는데,
이는 문서를 읽어도(영어도 마찬가지) 아직 정확하게 이해하지는 못했습니다.
다만 절대 경로가 //로 시작한다는 것만 파악했네요.

이로써 루트 페이지를 이동한 다음 내부에서는 Xamarin처럼 await Navigation.PushAsync(new NextPage())를 사용할 수 있습니다.
이 경우 자동으로 NavigationPage 형태로 판단하여 아래 그림과 같이 뒤로가기 아이콘이 있는 바가 생깁니다.


마무리

정리하자면 MAUI에 새로 생긴 Shell은 루트 페이지 변경 및 일반적인 페이지 이동으로 사용할 수 있으며 경로는 Uri 형식을 사용하고 그 위치는 Shell에 정의된 Depth를 따릅니다.
물론 기존 Xamarin과 같이 페이지를 이동하는 것도 가능합니다.
이로써 제가 이해한 바로는 기존에 App 클래스 내부의 MainView가 강하게 연결되어 있던 것을 느슨하게 결합할 수 있도록 프로그래밍 적으로 해소한 것으로 보이며, 이는 다양한 시나리오에서 사용이 가능할 것 같습니다.

좋아요 8

멋진 포스트 입니다!

좋아요 2