0% found this document useful (0 votes)
43 views

Cabañasrd, From Native To Cross-Platform With Xamarin Forms (2/4)

This document discusses implementing search functionality and displaying search results on a map in a cross-platform mobile app built with Xamarin Forms. It describes adding a search bar overlay on the map, binding it to an entry field. When text is entered, results will be displayed in a collection view overlaying the entire screen with motel name and other details. Markup is provided to layout the maps, search bar and results display.

Uploaded by

hsuyip
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views

Cabañasrd, From Native To Cross-Platform With Xamarin Forms (2/4)

This document discusses implementing search functionality and displaying search results on a map in a cross-platform mobile app built with Xamarin Forms. It describes adding a search bar overlay on the map, binding it to an entry field. When text is entered, results will be displayed in a collection view overlaying the entire screen with motel name and other details. Markup is provided to layout the maps, search bar and results display.

Uploaded by

hsuyip
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

CabañasRD, from native to cross-platform with Xamarin Forms [2/4]. about:reader?url=http://talkwithangel.com/cabanasrd-from-native-to-cr...

talkwithangel.com

CabañasRD, from native to cross-


platform with Xamarin Forms [2/4].
Angel Garcia

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.

The plan is to divide all the process in 4 parts:

1. From Adobe XD to XAML: Design and structure.

2. Implementing the command for opening native map, app icons,


splash screens, info tab and also the search functionality over
the map (this post).

3. Moving the data to the cloud: Let’s make our backend with
Azure Functions and CosmosDB and consume it from the app.

4. Implementing continuous integration and continuous delivery


with App Center.

Implementing the command for opening native


map, app icons, splash screens, info tab and also
the search functionality over the map.

Let’s start by looking at the search functionality, this is how it


looks over the map:

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...

We already have this map screen using a grid:

<?xml version="1.0" encoding="UTF-8" ?>

<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"

InitialCameraUpdate="18.7993522, -70.7474826, 7.5, 0, 0"

ItemsSource="{Binding Locations}"

MapType="Street"

VerticalOptions="FillAndExpand">

<maps:Map.ItemTemplate>

<DataTemplate>

<maps:Pin

Address="(Presione para ver detalles)"

Icon="{Binding Icon}"

Label="{Binding Motel.Name}"

Position="{Binding Position}" />

</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>

So we are going to start adding a frame in the same position as


the map in the grid and inside the frame we will need to have
something like this:

Let’s do the markup for this in the MotelsMapPage.xaml (look at


the Search Bar area):

<?xml version="1.0" encoding="UTF-8" ?>

<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"

InitialCameraUpdate="18.7993522, -70.7474826, 7.5, 0, 0"

ItemsSource="{Binding Locations}"

MapType="Street"

VerticalOptions="FillAndExpand">

<maps:Map.ItemTemplate>

<DataTemplate>

<maps:Pin

Address="(Presione para ver detalles)"

Icon="{Binding Icon}"

Label="{Binding Motel.Name}"

Position="{Binding Position}" />

</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>

<!-- SEARCH BAR -->

<Frame

Margin="10,50"

Padding="0"

BackgroundColor="#FFFFFF"

CornerRadius="20"

HasShadow="False"

VerticalOptions="Start">

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*" />

<ColumnDefinition Width="40" />

</Grid.ColumnDefinitions>

<Entry

Grid.Column="0"

Margin="0,0,0,-2"

BackgroundColor="#FFFFFF" />

<Image Grid.Column="1" Margin="0,0,15,0">

<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="&#xf002;"

Color="#FFC670" />

</Image.Source>

</Image>

</Grid>

</Frame>

<!-- END SEARCH BAR -->

</Grid>

</ContentPage.Content>

</ContentPage>

Run the app and see the results:

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...

Now, for showing the results of our search, we need to overlay


the entire main grid, adding a StackLayout as a container with a
ListView inside will make the trick, place the following before the
search bar:

<!-- SEARCH RESULTS LAYOUT -->

<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 Margin="20,120,20,0" ItemsSource="


{Binding Locations}">

<CollectionView.ItemTemplate>

<DataTemplate>

<Grid>

<Grid.RowDefinitions>

<RowDefinition Height="70" />

<RowDefinition Height="Auto" />

</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>

<!-- END SEARCH RESULTS LAYOUT -->

As you can see, we are reusing the same Locations


ObservableCollection for binding the results, we are going to
change it later, before running the app, we will more locations to
be added to the list, go to App/CabanasRD/Framework
/DataSources/InMemoryMotelsSource.cs and add more items,
like this:

using System;

using System.Collections.Generic;

using System.Threading.Tasks;

using CabanasRD.Data.Motels;

using CabanasRD.Domain.Motels;

namespace CabanasRD.Framework.DataSources

public class InMemoryMotelsSource: IMotelsSource

public async Task<IReadOnlyList<Motel>> GetAll()

await Task.Delay(1000);

return new List<Motel>

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,

Name = "Motel Cuarto Frío",

Images = new List<MotelImage>{

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"

},

Phones = new List<MotelPhone>{

new MotelPhone{ Number = "809-000-0000"},

new MotelPhone{ Number = "829-000-0000"},

new MotelPhone{ Number = "849-000-0000"}

},

Services = new List<MotelService>{

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 {

Name = "Vice Presidencial",

Price = 1050.00

},

new MotelService {

Name = "Presidencial",

Price = 1350.00

},

new Motel{

Id = 3,

Latitude = 18.502296,

Longitude = -69.864370,

Name = "El Real Placer",

Images = new List<MotelImage>{

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"

},

Phones = new List<MotelPhone>{

new MotelPhone{ Number = "809-000-0000"},

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 MotelPhone{ Number = "829-000-0000"},

new MotelPhone{ Number = "849-000-0000"}

},

Services = new List<MotelService>{

new MotelService {

Name = "Normal",

Price = 725.00

},

new MotelService {

Name = "Ejecutiva",

Price = 925.00

},

new MotelService {

Name = "Vice Presidencial",

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,

Name = "La Escuelita",

Images = new List<MotelImage>{

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"

},

Phones = new List<MotelPhone>{

new MotelPhone{ Number = "809-000-0000"},

new MotelPhone{ Number = "829-000-0000"},

new MotelPhone{ Number = "849-000-0000"}

},

Services = new List<MotelService>{

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 {

Name = "Vice Presidencial",

Price = 1050.00

},

new MotelService {

Name = "Presidencial",

Price = 1350.00

};

Ok, now play run:

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.

We also need to do some changes in the way we have the


bindings, before start modifying our map logic, let’s add the
package Xamarin.Forms.GoogleMaps.Bindings in the shared

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.

Now modify the following:

//Modify the MotelLocation.cs and put it like this

public class MotelLocation

public Motel Motel { get; set; }

public Pin Pin { get; set; }

//Add the following Binding Properties to the


MotelsMapPageViewModel:

private IList<MotelLocation> searchResultLocations;

public IList<MotelLocation> SearchResultLocations

get { return searchResultLocations; }

set { SetProperty(ref searchResultLocations, value); }

public ObservableCollection<Pin> Pins { get; set; }

public DelegateCommand TextSearchChangedCommand { get;


private set; }

private const string addressLabel = "(Presione para ver detalles)";

private bool isSearching;

public bool IsSearching

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...

get { return isSearching; }

set { SetProperty(ref isSearching, value); }

private Pin selectedPin;

public Pin SelectedPin

get { return selectedPin; }

set { SetProperty(ref selectedPin, value); }

private string searchText = "";

public string SearchText

get { return searchText; }

set

SetProperty(ref searchText, value);

private MotelLocation selectedLocation;

public MotelLocation SelectedLocation

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...

get { return selectedLocation; }

set {

SetProperty(ref selectedLocation, value);

if (selectedLocation != null)

SelectedPin = selectedLocation.Pin;

IsSearching = false;

//Add the following init to the MotelsMapPageViewModel


constructor:

Pins = new ObservableCollection<Pin>();

SearchResultLocations = new List<MotelLocation>();

TextSearchChangedCommand = new
DelegateCommand(TextSearchChanged);

//Add the following method to the MotelsMapPageViewModel:

private void 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;

var results = Locations.Where(l =>


l.Motel.Name.ToUpper().Contains(SearchText.ToUpper())).ToList();

SearchResultLocations = results;

else

IsSearching = false;

//Modify the LoadMotelsLocations method in the


MotelsMapPageViewModel:

private async void LoadMotelsLocations()

foreach (var item in await _getAllMotels.Invoke())

var pinItem = new Pin

Position = new Position(item.Latitude, item.Longitude),

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

};

//TODO: [Enhancement] Map from Domain to UI Model using


AutoMapper

Locations.Add(new MotelLocation

Pin = pinItem,

Motel = item

});

Pins.Add(pinItem);

//Modify the ItemsSource prop to the CollectionView for the


SEARCH RESULTS LAYOUT:

ItemsSource="{Binding SearchResultLocations}"

//Add the following prop to the Map view:

SelectedPin="{Binding SelectedPin}"

//Remove the following prop to the Map view:

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>

<bindings:BindingPinsBehavior Value="{Binding Pins}" />

</maps:Map.Behaviors>

//Add the following prop to the StackLayout for the SEARCH


RESULTS LAYOUT:

IsVisible="{Binding IsSearching}"

//Add the following prop to the Entry for the SEARCH BAR:

Text="{Binding SearchText}"

//Add the following prop to the CollectionView for the SEARCH


RESULTS LAYOUT:

SelectedItem="{Binding SelectedLocation}"

SelectionMode="Single"

//Add this behaviour to the Entry for the SEARCH BAR:

<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.

Xamarin.Essentials.Map helps us to manage this task, add the


following to complete the implementation:

//Add the Command prop to the button in the


MotelDetailsPage.xaml

Command="{Binding NavigateToLocationCommand}"

//Add the Command definition in the


MotelDetailsPageViewModel.cs

public DelegateCommand NavigateToLocationCommand {


get; set; }

//Remember to init it in the constructor

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...

DelegateCommand(async () => await


NavigateToLocation());

//Add the Command function

public async Task NavigateToLocation()

var location = new Location(Motel.Latitude,


Motel.Longitude);

var options = new MapLaunchOptions { NavigationMode =


Xamarin.Essentials.NavigationMode.Driving };

try

await Xamarin.Essentials.Map.OpenAsync(location,
options);

catch (Exception ex)

// No map application available to open or placemark can


not be located

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...

I use two web tools for generating the icons:

For iOS: https://appicon.co/

For Android: https://romannurik.github.io/AndroidAssetStudio


/icons-launcher.html

In iOS is super straightforward to change the icon, just go to the


Assets.xcassets in the iOS project and replace the icons for the
generated ones.

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...

“icon” and other named “launcher_foreground”, then replace


them in the mipmaps folders, sometimes is necessary to delete
the obj folder for the Android project when you see the icon
doesn’t update.

Well done, time for the splash screens!

Follow the official Xamarin docs for creating splash screens:

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

For Android use the following code for the splash_screen.xml:

<?xml version="1.0" encoding="utf-8"?>

<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...

Before going to the XAML, export and add the “.NET


Dominicana” image for both platforms and name it
“dotnetdo.png”.

Now go to App/CabanasRD/UI, create a folder for holding the


info view, name it “Info”, inside the new folder add two more
folders “Views” and “ViewModels”.

In App/CabanasRD/UI/Info/Views create a XAML called


“InfoPage” and in App/CabanasRD/UI/Info/ViewModels create
the “InfoPageViewModel.cs” that inherits from ViewModelBase,
and finally register this new view in the App.xaml.cs.

To use this InfoPage as the second tab, modify the


MainTabbedPage.xaml, replace the default content page that
we are using as second tab for this:

<info:InfoPage Title="Información" Visual="Material">

<ContentPage.IconImageSource>

<FontImageSource FontFamily="Font-Awesome-Solid"
Glyph="&#xf05a;" />

</ContentPage.IconImageSource>

</info:InfoPage>

This is a simple layout compared with the ones we have done


before in this app, check it out:

<?xml version="1.0" encoding="UTF-8" ?>

<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>

<RowDefinition Height="Auto" />

<RowDefinition Height="Auto" />

<RowDefinition Height="Auto" />

<RowDefinition Height="Auto" />

</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...

Text="CabañasRD Community Edition"

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"

Text="Hecho con amor por la comunidad de @dotnetdo"

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"

Text="Xamarin.Forms &#10; Xamarin.Essentials &#10;


Prism.Unity.Forms &#10; Xamarin.Forms.GoogleMaps &#10;
Xamarin.Forms.PancakeView &#10;
Xamarin.FFImageLoading.Svg.Forms &#10;
Xamarin.Forms.GoogleMaps.Bindings"

TextColor="#FFFFFF" />

</yummy:PancakeView>

</Grid>

</ScrollView>

</ContentPage.Content>

</ContentPage>

Run the app and move to the second tab:

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...

Yessir, we are done!

[UPDATE]: I posted in my twitter the link for the streaming and a


video with the final results:

See you in the next post of this serie!

See the code on Github

37 of 37 11/28/2020, 4:05 PM

You might also like