Xamarin.Forms – przykładowa aplikacja mobilna
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.
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.
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.
Podsumowanie
Gotowy projekt przykładowej aplikacji dostępny jest pod adresem https://github.com/Ermlab/xamarin-demo-page





