Cabañasrd, From Native To Cross-Platform With Xamarin Forms (2/4)
Cabañasrd, From Native To Cross-Platform With Xamarin Forms (2/4)
talkwithangel.com
40-51 minutes
So, following my last post, let’s continue with the second part of
this series of blogs about migrating and redesigning an existing
and popular app: CabañasRD.
3. Moving the data to the cloud: Let’s make our backend with
Azure Functions and CosmosDB and consume it from the app.
1 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<ContentPage
x:Class="CabanasRD.UI.Map.Views.MotelsMapPage"
xmlns="http://xamarin.com/schemas/2014/forms"
2 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;
assembly=Xamarin.Forms.GoogleMaps"
NavigationPage.HasNavigationBar="False">
<ContentPage.Content>
<Grid>
<maps:Map
x:Name="MotelsMap"
HorizontalOptions="FillAndExpand"
InfoWindowClicked="InfoWindowClicked"
ItemsSource="{Binding Locations}"
MapType="Street"
VerticalOptions="FillAndExpand">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin
Icon="{Binding Icon}"
Label="{Binding Motel.Name}"
</DataTemplate>
</maps:Map.ItemTemplate>
3 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
</maps:Map>
</Grid>
</ContentPage.Content>
</ContentPage>
<ContentPage
x:Class="CabanasRD.UI.Map.Views.MotelsMapPage"
4 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;
assembly=Xamarin.Forms.GoogleMaps"
NavigationPage.HasNavigationBar="False">
<ContentPage.Content>
<Grid>
<maps:Map
x:Name="MotelsMap"
HorizontalOptions="FillAndExpand"
InfoWindowClicked="InfoWindowClicked"
ItemsSource="{Binding Locations}"
MapType="Street"
VerticalOptions="FillAndExpand">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin
Icon="{Binding Icon}"
Label="{Binding Motel.Name}"
</DataTemplate>
5 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
</maps:Map.ItemTemplate>
</maps:Map>
<Frame
Margin="10,50"
Padding="0"
BackgroundColor="#FFFFFF"
CornerRadius="20"
HasShadow="False"
VerticalOptions="Start">
<Grid>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Entry
Grid.Column="0"
Margin="0,0,0,-2"
BackgroundColor="#FFFFFF" />
<Image.Source>
<FontImageSource
6 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
FontFamily="Font-Awesome-Solid"
Glyph=""
Color="#FFC670" />
</Image.Source>
</Image>
</Grid>
</Frame>
</Grid>
</ContentPage.Content>
</ContentPage>
7 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<StackLayout
BackgroundColor="#F8F8F8"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
8 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Label
Grid.Row="0"
FontSize="20"
Text="{Binding Motel.Name}"
TextColor="#F59302"
VerticalTextAlignment="Center" />
<BoxView
Grid.Row="1"
BackgroundColor="#BFBFBF"
HeightRequest="1" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
9 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
</CollectionView>
</StackLayout>
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CabanasRD.Data.Motels;
using CabanasRD.Domain.Motels;
namespace CabanasRD.Framework.DataSources
await Task.Delay(1000);
10 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
new Motel{
Id = 2,
Latitude = 18.4895593,
Longitude = -69.8247819,
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
11 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
},
new MotelService {
Name = "Normal",
Price = 725.00
},
new MotelService {
Name = "Ejecutiva",
Price = 925.00
12 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
},
new MotelService {
Price = 1050.00
},
new MotelService {
Name = "Presidencial",
Price = 1350.00
},
new Motel{
Id = 3,
Latitude = 18.502296,
Longitude = -69.864370,
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
13 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
14 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
},
new MotelService {
Name = "Normal",
Price = 725.00
},
new MotelService {
Name = "Ejecutiva",
Price = 925.00
},
new MotelService {
Price = 1050.00
},
new MotelService {
Name = "Presidencial",
Price = 1350.00
},
15 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
new Motel{
Id = 4,
Latitude = 18.492438,
Longitude = -69.907610,
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
16 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
new MotelImage {
Url = "https://c2.peakpx.com/wallpaper/604/823/790/castle-
fortress-defense-architecture-wallpaper-preview.jpg"
},
new MotelImage {
Url = "https://media.npr.org/assets/img/2015/08/15
/robin1-8aea039fd0710bd0c8549c19abab4085e0e3024c-
s800-c85.jpg"
},
},
new MotelService {
Name = "Normal",
Price = 725.00
},
new MotelService {
Name = "Ejecutiva",
Price = 925.00
17 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
},
new MotelService {
Price = 1050.00
},
new MotelService {
Name = "Presidencial",
Price = 1350.00
};
18 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
Cool! Now let’s add some logic to make this work as expected,
first let’s control the visibility of the search results putting
IsVisible bound to our ViewModel, then create the real collection
for the CollectionView’s ItemSource.
19 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
project.
20 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
set
21 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
set {
if (selectedLocation != null)
SelectedPin = selectedLocation.Pin;
IsSearching = false;
TextSearchChangedCommand = new
DelegateCommand(TextSearchChanged);
if (SearchText.Length > 0)
22 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
SelectedLocation = null;
IsSearching = true;
SearchResultLocations = results;
else
IsSearching = false;
Icon = BitmapDescriptorFactory.FromBundle(markerIcon),
Label = item.Name,
23 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
Address = addressLabel
};
Locations.Add(new MotelLocation
Pin = pinItem,
Motel = item
});
Pins.Add(pinItem);
ItemsSource="{Binding SearchResultLocations}"
SelectedPin="{Binding SelectedPin}"
ItemsSource="{Binding Locations}"
//Add the following Behaviors to the Map view (and add the
bindings namespace):
24 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<maps:Map.Behaviors>
</maps:Map.Behaviors>
IsVisible="{Binding IsSearching}"
//Add the following prop to the Entry for the SEARCH BAR:
Text="{Binding SearchText}"
SelectedItem="{Binding SelectedLocation}"
SelectionMode="Single"
<Entry.Behaviors>
<b:EventToCommandBehavior
Command="{Binding TextSearchChangedCommand}"
EventName="TextChanged" />
</Entry.Behaviors>
Run the app and try the search bar, click on any result and see
that we already can select the pin through the result of the
search.
25 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
Do you remember the “VER RUTA” button in the details view for
the motel? It’s time to add the command for opening the native
map in the device when we tap in the button.
Command="{Binding NavigateToLocationCommand}"
NavigateToLocationCommand = new
26 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
try
await Xamarin.Essentials.Map.OpenAsync(location,
options);
For the app icons, first export your icon image with a min
resolution of 1024 x 1024 (in pixels).
27 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
In Android, for not modifying any code and just update the icon
image, we will need to generate 2 set of icons, one named
28 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
iOS: https://docs.microsoft.com/en-us/xamarin/ios/app-
fundamentals/images-icons/launch-screens
29 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
Android: https://docs.microsoft.com/en-us/xamarin/android/user-
interface/splash-screen
<layer-list xmlns:android="http://schemas.android.com
/apk/res/android">
<item>
<color android:color="@color/launcher_background"/>
</item>
<item android:gravity="center"
android:width="200dp"
android:height="200dp">
30 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<bitmap
android:src="@drawable/logo"
android:gravity="fill_horizontal|fill_vertical"/>
</item>
</layer-list>
31 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
And finally we are going to markup the page for the Info tab and
will look like this:
32 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<ContentPage.IconImageSource>
<FontImageSource FontFamily="Font-Awesome-Solid"
Glyph="" />
</ContentPage.IconImageSource>
</info:InfoPage>
<ContentPage
x:Class="CabanasRD.UI.Info.Views.InfoPage"
33 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;
assembly=Xamarin.Forms.Core"
xmlns:yummy="clr-namespace:Xamarin.Forms.PancakeView;
assembly=Xamarin.Forms.PancakeView"
ios:Page.UseSafeArea="true">
<ContentPage.Content>
<ScrollView>
<Grid>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Label
Grid.Row="0"
Margin="10,50,10,50"
FontFamily="Roboto-Bold"
FontSize="24"
HorizontalTextAlignment="Center"
34 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
TextColor="#848484" />
<Image
Grid.Row="1"
Aspect="AspectFit"
Source="dotnetdo" />
<Label
Grid.Row="2"
Margin="10,80,10,0"
FontFamily="Roboto-Light"
FontSize="16"
HorizontalTextAlignment="Center"
TextColor="#848484" />
<yummy:PancakeView
Grid.Row="3"
Margin="20,10"
Padding="20,20,20,30"
BackgroundGradientEndColor="#EEA849"
BackgroundGradientStartColor="#F46B45"
CornerRadius="20"
HorizontalOptions="FillAndExpand">
35 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
<Label
FontFamily="Roboto-Light"
FontSize="16"
HorizontalTextAlignment="Start"
LineHeight="2"
TextColor="#FFFFFF" />
</yummy:PancakeView>
</Grid>
</ScrollView>
</ContentPage.Content>
</ContentPage>
36 of 37 11/28/2020, 4:05 PM
CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...
37 of 37 11/28/2020, 4:05 PM