71

Practical Xamarin - · PDF fileTraditional Xamarin Approach With Xamarin.Forms: More code-sharing, all native Windows-specific C# Android-specific C# iOS-specific C# C# Shared Logic

  • Upload
    buikiet

  • View
    218

  • Download
    0

Embed Size (px)

Citation preview

The finished application

DEMO

Shared C# codebase • 100% native API access • High performance

Windows-specific

C#

Android-specific

C#

iOS-specific

C#

C# Shared Logic

Java

Android Studio

in

Android codebaseiOS codebase

Objective-C

XCode

inC#

Visual Studio

in

Windows codebase

Windows-

specific C#

Android-

specific C#

iOS-specific

C#

C# Shared Logic

Java

Android Studio

in

Android codebaseiOS codebase

Objective-C

XCode

inC#

Visual Studio

in

Windows codebase

Traditional Xamarin

Approach

With Xamarin.Forms:

More code-sharing, all native

Windows-

specific C#

Android-specific

C#

iOS-specific

C#

C# Shared Logic

Java

Android Studio

in

Android codebaseiOS codebase

Objective-C

XCode

inC#

Visual Studio

in

Windows codebase

Xamarin.Forms

C# Shared Logic

Java

Android Studio

in

Android codebaseiOS codebase

Objective-C

XCode

inC#

Visual Studio

in

Windows codebase

Can be shared

✓ 40+ Pages, layouts, and controls

(Build from code behind or XAML)

✓ Two-way data binding

✓ Navigation

✓ Animation API

✓ Dependency Service

✓ Messaging Center

✓ Easy for applying MVVM (yay)

Xamarin.Forms

C# Shared Logic

Java

Android Studio

in

Android codebaseiOS codebase

Objective-C

XCode

inC#

Visual Studio

in

Windows codebase

public partial class App : Application{public App(){InitializeComponent();

MainPage = new App5.MainPage();}

}

<ContentPage><Label Text="Welcome to Joe's Burger Store" FontSize="25"></Label>

<Entry StyleId="UserId" Text="{Binding Path=Username}" Placeholder="Username" />

<Entry StyleId="PasswordId" Text="{Binding Path=Password}" Placeholder="Password" IsPassword="true" />

<Grid HorizontalOptions="Center"><Button x:Name="loginButton"

Command="{Binding LoginCommand}" Text="Login" Grid.Row="0" Grid.Column="0"/>

<Button x:Name="helpButton" Command="{Binding HelpCommand}" Text="Help" Grid.Row="0" Grid.Column="1" />

</Grid></StackLayout>

</ContentPage>

Layouts

Pages

Stack Absolute Relative Grid ContentView ScrollView Frame

Content MasterDetail Navigation Tabbed Carousel

<StackLayout Padding="32" Spacing="32"><BoxView Color="#FFF25022" HeightRequest="128" /><BoxView Color="#FF7FBA00" HeightRequest="128" /><BoxView Color="#FF01A4EF" HeightRequest="128" /><BoxView Color="#FFFFB901" HeightRequest="128" />

</StackLayout>

<Grid Padding="32" RowSpacing="32" ColumnSpacing="32"><Grid.RowDefinitions><RowDefinition Height="*" /><RowDefinition Height="*" />

</Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" />

</Grid.ColumnDefinitions><BoxView Grid.Row="0" Grid.Column="0" Color="#FFF25022" /><BoxView Grid.Row="0" Grid.Column="1" Color="#FF7FBA00" /><BoxView Grid.Row="1" Grid.Column="0" Color="#FF01A4EF" /><BoxView Grid.Row="1" Grid.Column="1" Color="#FFFFB901" />

</Grid>

ActivityIndicator BoxView Button DatePicker Editor

Entry Image Label ListView Map

OpenGLView Picker ProgressBar SearchBar Slider

Stepper TableView TimePicker WebView EntryCell

ImageCell SwitchCell TextCell ViewCell

<DatePicker />

File New Project

DEMO

var httpClient = new HttpClient();var response = await httpClient.GetAsync(new Uri("http://www.joesburgerstore.com/burgers"));

if (!response.IsSuccessStatusCode)throw new HttpRequestException(response.ReasonPhrase);

string jsonResponse = await response.Content.ReadAsStringAsync();

Architecture of the Shared Project

DEMO

Data Model

View

XAML

Code-Behind

Event Handlers

Data Model

View

XAML

Code-Behind

View Model

State +

Operations

Change notification

Data-binding and commands

View Model

View Model

View Model View Model

View Model

View Model

View Model View Model

Data Model

View

XAML

Code-

Behind

Data Model

View

XAML

Code-

Behind

Message

View Model

State +

Operations

View Model

State +

Operations

View

XAML

Code-

Behind

MessageMessaging

Center (XF)

View Model

State +

Operations

Publish messages

Subscribe to messages

Looking at the view models

DEMO

<Label Text="{Binding SelectedBurger.Name}" /><Label Text="{Binding SelectedBurger.ShortDescription}" /><Label Text="{Binding SelectedBurger.Price}" />

public partial class BurgerDetailView : BaseContentPage{

//private BurgerDetailViewModel viewModel;public BurgerDetailView(){

InitializeComponent();}

public BurgerDetailView(object objectToPass){

InitializeComponent();ViewModel = new BurgerDetailViewModel();this.BindingContext = ViewModel;

}}

public interface ICommand{

event EventHandler CanExecuteChanged;bool CanExecute(object parameter);void Execute(object parameter);

}

<Button Text="Add to cart" Command="{Binding AddToCartCommand}"></Button>

<Button Text="Read description" Command="{Binding ReadDescriptionCommand}"></Button>

<ContentPagexmlns:local="clr-namespace:JoesBurgerStore;assembly=JoesBurgerStore">

...<ListView x:Name="listView" IsGroupingEnabled="true" ItemsSource="{Binding BurgerGroups}">

<ListView.Behaviors><utility:EventToCommandBehavior

EventName="ItemSelected" Command="{Binding BurgerSelectedCommand}" Converter="{StaticResource localSelectedItemEventArgsToSelectedItemConverter}"

/></ListView.Behaviors>

...</ListView>

Data binding the Views

DEMO

this.MainPage = new NavigationPage(new MasterPage());

Navigation

DEMO

<ListView RowHeight="80"ItemsSource="{Binding Recipes}"><ListView.ItemTemplate><DataTemplate>

<ImageCellImageSource="{Binding Image}"Text="{Binding Title}" />

</DataTemplate></ListView.ItemTemplate>

</ListView>

Building the UI

DEMO

Label

LabelRenderer

LabelRenderer

LabelRenderer TextBlock

TextView

UILabel

public class RoundButton: Button{

}

<customRenderers:RoundButton Text="Order burgers" Command="{Binding OrderBurgersCommand}"></customRenderers:RoundButton>

[assembly: ExportRenderer(typeof(RoundButton), typeof(RoundButtonRenderer))]namespace JoesBurgerStore.iOS.CustomRenderers{

public class RoundButtonRenderer : ButtonRenderer{

protected override void OnElementChanged(ElementChangedEventArgs<Button> e){

base.OnElementChanged(e);if (Control != null){

var button = (RoundButton)e.NewElement;

button.SizeChanged += (s, args) =>{

var radius = Math.Min(button.Width, button.Height) / 2.0;button.BorderRadius = (int)(radius);

};}

}}

Custom renderers

DEMO

<BoxView HorizontalOptions="Center"><BoxView.Color><OnPlatform x:TypeArguments="Color"

iOS="Green" Android="#738182" WinPhone="Accent" />

</BoxView.Color><BoxView.WidthRequest><OnPlatform x:TypeArguments="x:Double"

iOS="30" Android="40" WinPhone="50" />

</BoxView.WidthRequest></BoxView>

Handling platform-specifics

DEMO