Xamarin.Forms – przykładowa aplikacja mobilna

 In Mobile, Technicznie

Etap 1 – instalacja i założenie projektu

Tworzenie każdej aplikacji Xamarin, w tym naszej przykładowej aplikacji mobilnej, należy zacząć od zainstalowania Xamarina na każdym potrzebnym komputerze. Pod adresem http://xamarin.com/download znajduje się oprogramowanie instalujące wszystkie wymagane rzeczy, takie jak Xamarin, Xamarin Studio, integrację z Visual Studio kończąc na SDK platform mobilnych. Chcąc programować na 3 największe platformy Android, iOS i Windows Phone konieczne są co najmniej dwa komputery, jeden z Windowsem 8 lub 10 który umożliwia obsługę Androida i Windows Phone, oraz drugi Mac firmy Apple który umożliwia obsługę Androida i iOS. Ponieważ potrzeba będzie często przełączać się pomiędzy dwoma różnymi komputerami, nieodzownym elementem jest program typu GIT.

Z poziomu Visual Studio należy przejść do zakładania nowego projektu poprzez wybranie menu File->New->Project, z zainstalowanych szablonów wybrać język C#, następnie Mobile Apps oraz Blank App(Xamarin.Forms Portable), uzupełnić nazwę i ścieżkę projektu.

Img1

Została stworzona solucja z 4 projektami, pierwsza z kodem wspólnym, oraz kolejne dla każdej z platform. Wybór aktualnej platformy odbywa się poprzez kliknięcie prawym przyciskiem na projekcie specyficznej platformy w oknie Solution Explorer i wybranie Set as StartUp Project. W części wspólnej należy stworzyć 4 foldery Model, Service, View i ViewModel. Tak przygotowany projekt można traktować jako bazę dla każdej aplikacji Xamarin.Forms.

Img2

Etap 2 – pierwsza strona

W celu stworzenia pierwszej strony należy kliknąć prawym na folder View, wybrać Add->NewItem, następnie Forms Xaml Page i podać nazwę MainPage.cs

W pliku MainPage.xaml należy uzupełnić kod pierwszej strony.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Demo.View.MainPage">

    <StackLayout>
        <Label Text="Główna strona aplikacji demo" />
        <Entry Text="" Placeholder="Wprowadź tekst" />
        <Label Text="Wprowadzono 0 znaków" />
        <Button Text="Oblicz magiczny tekst" />
        <Label Text="Nie obliczono" />
        <Button Text="Przejdź do drugiej strony" />
    </StackLayout>
</ContentPage>

Kod pliku MainPage.xaml.cs

using Xamarin.Forms;

namespace Demo.View
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            NavigationPage.SetHasNavigationBar(this, false);
        }
    }
}

Kod pliku App.cs

using Demo.View;
using Xamarin.Forms;

namespace Demo
{
    public class App : Application
    {
        public static INavigation Navigation = null;

        public App()
        {
            NavigationPage page = new NavigationPage(new MainPage());
            App.Navigation = page.Navigation;
            MainPage = page;
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Tak zaprogramowany projekt można już uruchomić na dowolnej z platform, na fizycznym smartfonie lub emulatorze.

Etap 3 – MVVM

Aplikacje Xamarin.Forms zoptymalizowane są pod wzorzec projektowania MVVM tzn. Model-View-ViewModel. Oznacza to że każdy Page reprezentujący View powiązany jest z odpowiadającym mu ViewModel. ViewModel zawiera wiele pól i poleceń, pod które bindują się kontrolki z View, które obserwują je i reagują na ich zmiany. Cały mechanizm oparty jest na interfejsie INotifyPropertyChanged, dlatego implementację MVVM najlepiej zacząć od stworzenia pliku BaseViewModel, który będzie podstawą dla każdego pliku ViewModel.

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Demo.ViewModel
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Należy teraz stworzyć nowy plik MainViewModel, pod który zbinduje się MainPage.

using Demo.View;
using System.Windows.Input;
using Xamarin.Forms;

namespace Demo.ViewModel
{
    public class MainViewModel : BaseViewModel
    {
        string _normalText = "";
        string _magicText = "Nie obliczono";

        public MainViewModel()
        {
            this.DoMagicCommand = new Command(() =>
            {
                this.MagicText = string.Format("Magicznie powiększony tekst: {0}", this.NormalText.ToUpperInvariant());
            }, () =>
            {
                return !string.IsNullOrEmpty(this.NormalText);
            });

            this.NextPageCommand = new Command(() =>
            {
                //TODO
            });
        }

        public string NormalText
        {
            set
            {
                if (_normalText != value)
                {
                    _normalText = value;
                    OnPropertyChanged();
                    OnPropertyChanged("NormalTextLength");
                    OnPropertyChanged("NormalTextVisibility");
                    ((Command)this.DoMagicCommand).ChangeCanExecute();
                }
            }
            get
            {
                return _normalText;
            }
        }

        public string NormalTextLength
        {
            get
            {
                return string.Format("Wprowadzono {0} znaków", this.NormalText.Length);
            }
        }

        public bool NormalTextVisibility
        {
            get
            {
                return (this.NormalText.Length > 4);
            }
        }

        public string MagicText
        {
            set
            {
                if (_magicText != value)
                {
                    _magicText = value;
                    OnPropertyChanged();
                }
            }
            get
            {
                return _magicText;
            }
        }

        public ICommand DoMagicCommand { protected set; get; }
        public ICommand NextPageCommand { protected set; get; }
    }
}

Kod pliku MainPage.xaml.cs

using Demo.ViewModel;
using Xamarin.Forms;

namespace Demo.View
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            NavigationPage.SetHasNavigationBar(this, false);
            this.BindingContext = new MainViewModel();
        }
    }
}

Kod pliku MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Demo.View.MainPage">

    <StackLayout>
        <Label Text="Główna strona aplikacji demo" />
        <Entry Text="{Binding NormalText}" Placeholder="Wprowadź tekst" />
        <Label Text="{Binding NormalTextLength}" />
        <Label Text="Tekst ma więcej niż 4 znaki!" IsVisible="{Binding NormalTextVisibility}" />
        <Button Text="Oblicz magiczny tekst" Command="{Binding DoMagicCommand}" />
        <Label Text="{Binding MagicText}" />
        <Button Text="Przejdź do drugiej strony" Command="{Binding NextPageCommand}" />
    </StackLayout>
</ContentPage>

Można teraz przetestować obecne działanie aplikacji.

Etap 4 – więcej niż jedna strona

Kolejnym krokiem będzie dodanie kolejnej strony oraz nawigacji pomiędzy stronami aplikacji. W tym celu należy dodać nową Forms Xaml Page o nazwie SecondPage.cs

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Demo.View.SecondPage">

    <StackLayout>
        <Label Text="Druga strona" />
        <Label Text="{Binding LangCode}" />
    </StackLayout>
</ContentPage>

Nowa klasa SecondViewModel

namespace Demo.ViewModel
{
    public class SecondViewModel : BaseViewModel
    {
        string _langCode = "";

        public SecondViewModel()
        {
            this.LangCode = string.Format("Zaraz wykryjemy Twój język");
        }

        public string LangCode
        {
            set
            {
                if (_langCode != value)
                {
                    _langCode = value;
                    OnPropertyChanged();
                }
            }
            get
            {
                return _langCode;
            }
        }
    }
}

Kod pliku SecondPage.xaml.cs

using Demo.ViewModel;
using Xamarin.Forms;

namespace Demo.View
{
    public partial class SecondPage : ContentPage
    {
        public SecondPage()
        {
            InitializeComponent();
            NavigationPage.SetHasNavigationBar(this, false);
            this.BindingContext = new SecondViewModel();
        }
    }
}

Fragment pliku MainViewModel.cs

this.NextPageCommand = new Command(async () =>
    {
        await App.Navigation.PushAsync(new SecondPage());
    });

Można teraz przetestować obecne działanie aplikacji.

Etap 5 – odwołania do natywności

Ostatnim krokiem jest przykład usługi która potrzebuje odwołania do specyficznych cech każdej z platform, tzw. natywności. W tym celu należy utworzyć w folderze Service interfejs ILangService

namespace Demo.Service
{
    public interface ILangService
    {
        string GetLangCode();
    }
}

Dodatkowo należy stworzyć implementację tego interfejsu w każdym projekcie specyficznym dla platform. Kod pliku LangService dla Androida

using Demo.Service;
using Xamarin.Forms;

[assembly: Dependency(typeof(Demo.Droid.LangService))]
namespace Demo.Droid
{
    public class LangService : ILangService
    {
        public string GetLangCode()
        {
            var androidLocale = Java.Util.Locale.Default;

            return androidLocale.ToString().Replace("_", "-").TrimEnd('-');
        }
    }
}

Kod pliku LangService dla iOS

using Demo.Service;
using Foundation;
using Xamarin.Forms;

[assembly: Dependency(typeof(Demo.iOS.LangService))]
namespace Demo.iOS
{
    public class LangService : ILangService
    {
        public string GetLangCode()
        {
            var language = "en";

            if (NSLocale.PreferredLanguages.Length > 0)
            {
                var pref = NSLocale.PreferredLanguages[0];
                language = pref.Replace("_", "-");
            }

            return language;
        }
    }
}

Kod pliku LangService dla Windows Phone

using Demo.Service;
using Xamarin.Forms;

[assembly: Dependency(typeof(Demo.WinPhone.LangService))]
namespace Demo.WinPhone
{
    public class LangService : ILangService
    {
        public string GetLangCode()
        {
            return System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName;
        }
    }
}

Fragment pliku SecondViewModel.cs

public SecondViewModel()
    {
        ILangService langService = DependencyService.Get<ILangService>();

        this.LangCode = string.Format("Twój język to: {0}", langService.GetLangCode());
    }

Można teraz przetestować obecne działanie aplikacji.

Img3

Podsumowanie

Gotowy projekt przykładowej aplikacji dostępny jest pod adresem https://github.com/Ermlab/xamarin-demo-page

Img4

Recommended Posts