[Из песочницы] Xamarin.Forms Shell

В конце мая Microsoft выпустила в релиз Xamarin.Forms Shell — оболочку нацеленную на упрощение создания кроссплатформенных мобильных приложений и включающий в себя следующий функционал: боковое меню, вкладки, навигация, поиск.
Давайте начнем с создания пустого проекта Xamarin.Forms в Visual Studio 2019. Обратите внимание, на данный момент Shell официально поддерживает только 2 платформы: iOS и Android, UWP еще в стадии разработки. Рекомендую сразу же обновить все nuget пакеты в решении.

yclcpja1h4jin3ijgki_re_fbxu.png

Далее создадим производный от Shell класс AppShell, для этого в добавим XAML-файл в общий проект со следующим содержимым:

AppShell.xaml






AppShell.xaml.cs

namespace HelloShell
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class AppShell : Shell
    {
        public AppShell()
        {
            InitializeComponent();
        }
    }
}


после чего в файле App.xaml.cs указываем что в качестве MainPage у нас будет выступать AppShell:

public App()
{
    InitializeComponent();

    //MainPage = new MainPage();
    MainPage = new AppShell();
}


и пару ContentPage страниц: Page1 и Page2. Так же в нашем тестовом приложении будут использоваться изображения, поэтому добавим их в платформозависимые проекты, для андройд в папку Resources=>drawable, а для ios в папку Resources.

6sblnnotwqn01aqsktxh7g_ceoi.png

Боковое меню


miurciwdtqdbt_nolglgqhejsv4.png

Боковое меню (часто его называют гамбургер меню) представляет из себя выезжающее меню, которое можно вызвать по нажатию на кнопку или специальным жестом и включает в себя заголовок (Header), список страниц (Flyout Items) и меню (Flyout Menu)

AppShell.xaml




    
        
            
            
    
    
    
        
    
    
        
    
    
        
    
    



AppShell.xaml.cs

namespace HelloShell
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class AppShell : Shell
    {
        public AppShell()
        {
            InitializeComponent();
        }

        private async void MenuItem_Clicked(object sender, System.EventArgs e)
        {
            await DisplayAlert("","Привет Хабр!","OK");
        }
    }
}


Вкладки


yrcoyvv730kscyn8bri2zvedbym.png

Xamarin.Forms Shell в качестве корневого шаблона может поддерживать нижние и верхние вкладки, а так же их комбинацию:

AppShell.xaml.cs




    
        
            
        

        
            
            
        

        
            
        
    


Как видите, сделать это довольно просто. Еще одним преимуществом является эффективная загрузка страниц, которая позволяет инициализировать страницу только когда на нее переходит пользователь, что существенно ускоряет запуск приложения.

Навигация


Xamarin.Forms предоставляет улучшенную навигацию по интерфейсу на основе URI, позволяя переходить на любую страницу в приложении без соблюдения строгой иерархии и переходить назад без необходимости прохода всех страниц в стеке навигации. Чтобы навигация работала, страницу нужно зарегистрировать, сделать это можно в разметке XAML в FlyoutItem, Tab и ShellContent с помощью свойства Route


    
        
            
            
        
        
        
    
                      
    ...


или в коде

Routing.RegisterRoute("page1", typeof(Page1));


навигация осуществляется с помощью команды

await Shell.Current.GoToAsync("//page2");


В качестве примера внесем изменения в следующие файлы:

AppShell.xaml

    
        
            
        

        
            
            
        

        
            
        
    


MainPage.xaml

    
        


MainPage.xaml.cs

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private async void ToPage2(object sender, EventArgs e)
        {
            await Shell.Current.GoToAsync("//page2");
        }
    }


Page2.xaml

    
        
            


Page2.xaml.cs

    public partial class Page2 : ContentPage
    {
        public Page2()
        {
            InitializeComponent();
        }

        private async void Back(object sender, EventArgs e)
        {
            await Shell.Current.GoToAsync("//main");
        }
    }


Поиск


Xamarin.Forms Shell имеет встроенные функции поиска, предоставляемые классом SearchHandler. Чтобы добавить функцию поиска на страницу, мы создадим класс PetSearchHandler производный от SearchHandler и переопределим методы OnQueryChanged и OnItemSelected. Метод OnQueryChanged срабатывает при вводе пользователем текста в поисковое поле и принимает два аргумента: oldValue и newValue, которые содержат предыдущий и новый поисковый запрос соответственно.

Метод SelectedItem выполняется в момент выбора пользователем результата поиска и принимает в качестве параметров объект, в данном случае Animal.

Для примера создадим модель Animal

Models/Animal.cs

    public class Animal
    {
        public string Name { get; set; }
        public string ImageUrl { get; set; }
    }


Класс PetData который будет содержать коллекцию наших любимых кошечек и собачек

Data/PetData.cs

 public static class PetData
    {
        public static IList Pets { get; private set; }

        static PetData()
        {
            Pets = new List();

            Pets.Add(new Animal
            {
                Name = "Afghan Hound",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/6/69/Afghane.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Alpine Dachsbracke",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Alpejski_gończy_krótkonożny_g99.jpg/320px-Alpejski_gończy_krótkonożny_g99.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "American Bulldog",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/5/5e/American_Bulldog_600.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Abyssinian",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Gustav_chocolate.jpg/168px-Gustav_chocolate.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Arabian Mau",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/d/d3/Bex_Arabian_Mau.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Bengal",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Paintedcats_Red_Star_standing.jpg/187px-Paintedcats_Red_Star_standing.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Burmese",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/04/Blissandlucky11.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "Cyprus",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b9/CyprusShorthair.jpg/320px-CyprusShorthair.jpg"
            });

            Pets.Add(new Animal
            {
                Name = "German Rex",
                ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/c/c7/German_rex_harry_%28cropped%29.jpg"
            });
        }
    }


PetSearchHandler.cs

    public class PetSearchHandler : SearchHandler
    {
        protected override void OnQueryChanged(string oldValue, string newValue)
        {
            base.OnQueryChanged(oldValue, newValue);

            if (string.IsNullOrWhiteSpace(newValue))
            {
                ItemsSource = null;
            }
            else
            {
                ItemsSource = PetData.Pets
                    .Where(pet => pet.Name.ToLower().Contains(newValue.ToLower()))
                    .ToList();
            }
        }

        protected override async void OnItemSelected(object item)
        {
            base.OnItemSelected(item);
            var pet = item as Animal;
            if (pet is null) return;
            await App.Current.MainPage.DisplayAlert("Вы выбрали",pet.Name,"ok");
        }
    }


Добавим страницу Pets в которой зададим наш PetSearchHandler



    
        
    
    


В итоге у нас должна получиться страница с поисковым полем в навигационном баре, при вводе поисковой фразы отображается простой список из названий питомцев.

y7f6yayd-wbsb2zl8nqukmalem0.png

При желании мы легко можем настроить содержимое ячейки списка, добавив туда картинку и несколько текстовых меток:

    
        
            
                
                    
                        
                        
                
            
        
    


a5lik6wa5hvmx5l5ihwpbmrei8k.png

Исходники на github

© Habrahabr.ru