XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2016/06/30

Xamarin.Forms 使用者登入

使用者登入

在這一章節,您需要完成一個應用程式,其共有兩個頁面;當使用者開啟這個應用程式之後,首先會看到一個使用者要輸入帳號與密碼的頁面,在這個頁面中,當使用者輸入密碼的時候,必須要有 * 遮罩,避免其他人看到輸入的密碼,接著按下登入按鈕後,當輸入的帳號與密碼符合規定,則會進入到首頁頁面。
在進入到首頁頁面之後,若使用者按下回上一頁按鈕,是無法再度回到登入頁面,而是會直接結束這個應用程式的執行。
在這個範例中,也會加入使用 Font Awesome 功能,讓您可以在 核心PCL 內的 XAML,使用 字型圖示 功能來顯示更加豐富的視覺圖片。

建立使用者登入方案

  1. 首先,開啟您的 Visual Studio 2015
  2. 接著透過 Visual Studio 2015 功能表,選擇這些項目 檔案 > 新增 > 專案 準備新增一個專案。
  3. 接著,Visual Studio 2015 會顯示 新增專案 對話窗,請在這個對話窗上,進行選擇 Visual C# >Cross-Platform > Blank Xaml App (Xamarin.Forms Portable)
  4. 接著,在最下方的 名稱 文字輸入盒處,輸入 XamarinLogin 這個名稱,最後使用滑鼠右擊右下方的確定 按鈕。
  5. 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  6. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  7. 最後,整個新的 Xamarin.Forms 專案就建立完成了。

登入頁面

建立登入頁面

首先,要來建立一個登入頁面,先在方案總管內,找到 核心PCL 專案,在核心PCL 專案節點上,使用滑鼠右擊該節點,接著再彈出功能表中,選擇 加入 > 新增項目
準備建立登入頁面
在 加入新項目 - XamarinLogin 對話窗中,點擊 Visual C# > Cross-Platform > Forms Xaml Page
在下方名稱欄位右方的文字輸入盒中,輸入 LoginPage,最後,右擊 新增 按鈕,完成新增登入頁面的工作。
選擇新增Login頁面的類型
在 核心PCL 專案內,找到 App.xaml 這個節點,展開該節點,會看到 App.xaml.cs 這個節點,使用滑鼠雙擊該 App.xaml.cs 這個節點,打開這個檔案。
準備打開 App.xaml.cs檔案
在 App.xaml.cs 的建構式內,您會看到這個 Xamarin.Forms 應用程式,一旦啟動之後,會先開啟XamarinLogin.MainPage 這個頁面,作為該應用程式的起始顯示畫面,也就是整體 核心PCL 的進入點。
        public App()
        {
            InitializeComponent();

            MainPage = new XamarinLogin.MainPage();
        }
由於,這個應用程式在啟動之後,會先要求使用者輸入帳號密碼,在驗證正確之後,才會進入到主畫面,所以,在此,需要修正該應用程式啟動之後,第一個顯示的畫面,必須為 LoginPage 頁面。
不過,因為當使用者輸入完成帳號與密碼之後,將會切換到 MainPage 頁面,因此,在這需要將第一個顯示頁面物件,放入 NavigationPage 建構式的參數內,產出出一個 NavigationPage,再將其設定到App.MainPage 屬性上。
        public App()
        {
            InitializeComponent();

            var rootPage = new NavigationPage(new LoginPage());
            MainPage = rootPage;
        }
接著,需要修改登入頁面的視覺畫面與商業邏輯,請打開 核心PCL 專案內,剛剛新建立的 LoginPage.xaml這個檔案。
但當您在進行 XAML 宣告定義修改的時候,IntelliSense 沒有作用的話,請先重新編譯 XamarinLogin這個 核心PCL 專案。
在 LoginPage.xaml 頁面中的 ContentPage 頁面,使用到的 Title 這個屬性,定義了這個頁面的名稱。
在這個 LoginPage.xaml 頁面定義中,使用到一個 Grid 版面配置控制項,逐一將各個要顯示的控制項,透過 Grid.Row 這個附加屬性 (Attached Properties),指定控制項要放在 Grid 的哪個位置。
若再 Grid 版面配置控制巷內的任何控制項,沒有使用附加屬性來指定要放在 Grid 版面配置的哪個地方,則會預設使用 Grid.Row="0" Grid.Column="0"
<Label Text="歡迎來到 Xamarin.Forms"
           FontSize="40"
           Grid.Row="0"
           HorizontalTextAlignment="Center"
           />
上述的 Label 控制項,使用到了 HorizontalTextAlignment ,用來設定這個控制項要顯示的文字,需要置中顯示。
<Entry Placeholder="請輸入密碼"
           x:Name="entryPassword"
           Grid.Row="4"
           IsPassword="True"  />
上述的 Entry 控制項,使用了 IsPassword="True" 屬性值,定義該文字輸入盒所輸入的任何文字,會使用遮罩來替換,避免所輸入的密碼,被他人看到。
x:Name="entryPassword" 這個 x:Name 的延伸屬性用法,是要讓 Code Behind 的 C# 程式碼,可以存取這個控制項,亦即使用 entryPassword 這個變數名稱,就可以存取到這個控制項。
底下為修改 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="XamarinLogin.LoginPage"
             Title="使用者登入"
             >

  <Grid
    HorizontalOptions="FillAndExpand" VerticalOptions="Center"
    Padding="30,0"
      >
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Label Text="歡迎來到 Xamarin.Forms"
           FontSize="40"
           Grid.Row="0"
           HorizontalTextAlignment="Center"
           />
    <Label Text="帳號"
           Grid.Row="1"
           />
    <Entry Placeholder="請輸入帳號"
           x:Name="entryAccount"
           Grid.Row="2"
           HorizontalOptions="FillAndExpand"
             />
    <Label Text="密碼" 
           Grid.Row="3"/>
    <Entry Placeholder="請輸入密碼"
           x:Name="entryPassword"
           Grid.Row="4"
           IsPassword="True"  />
    <Button Text="登入"
            x:Name="buttonLogin"
            Grid.Row="5"
            HorizontalOptions="FillAndExpand"
              />
  </Grid>
</ContentPage>
在 LoginPage.xaml.cs Code Behind 程式碼內,首先看到建構式內,有呼叫NavigationPage.SetBackButtonTitle 這個方法,其目的是在於告知 NavigationPage ,當切換到別的頁面時候,需要設定 導航列 (Navigation Bar) 的返回按鈕旁的文字要顯示的內容。
其中,也在建構式中,定義了 buttonLogin 按鈕的點擊事件,當使用者點擊了登入按鈕,這個時候,會透過頁面內擁有 Navigation 屬性(這個屬性是 INavigation 類型),將要顯示的首頁物件,推到INavigation.NavigationStack 內,並且顯示這個頁面。
對於 Xamarin.Forms 系統而言,當要顯示一個新的頁面,就會將該新的頁面物件儲存到INavigation.NavigationStack 內,採用的資料結構是屬於 Stack 堆疊 型式;當要從新的頁面返回到原先的頁面,Xamarin.Forms 系統會從 INavigation.NavigationStack 資料結構內,將正在顯示的頁面物件移除,並且還原到最初的頁面。
所以,當要切換到新的頁面與要返回到原先頁面,可以使用下列方法:
  • 切換到新頁面 Navigation.PushAsync(NextPage)
  • 回到原先頁面 Navigation.PopAsync()
底下為 LoginPage.xaml.cs Code Behind 的程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace XamarinLogin
{
    public partial class LoginPage : ContentPage
    {
        public LoginPage()
        {
            InitializeComponent();

            NavigationPage.SetBackButtonTitle(this, "回登入頁面");
            buttonLogin.Clicked += ButtonLogin_Clicked;
        }

        private async void ButtonLogin_Clicked(object sender, EventArgs e)
        {
            // 切換到主頁面
            var NextPage = new MainPage();

            await Navigation.PushAsync(NextPage);
         }
    }
}

修改首頁頁面

在 MainPage.xaml 檔案中,只有在 ContentPage 物件內的 Title 屬性內,指定了這個頁面的名稱。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamarinLogin"
             x:Class="XamarinLogin.MainPage"
             Title="應用首頁"
             >

  <Label Text="Welcome to Xamarin Forms!"
           VerticalOptions="Center"
           HorizontalOptions="Center" />

</ContentPage>
在 MainPage.xaml.cs Code Behind 檔案中,也只有在建構式方法內,使用NavigationPage.SetBackButtonTitle 方法定義了回上一頁按鈕要顯示的名稱。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XamarinLogin
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

             NavigationPage.SetBackButtonTitle(this, "回到首頁");
        }
    }
}

執行察看結果

接下來看看分別在 Android 與 iOS 這兩個平台上,這個應用程式的執行結果。

Android 系統

  1. 請使用滑鼠右擊方案總管內的 XamarinLogin.Droid 專案節點,選擇 設定為起始專案 項目。
  2. 確認建置組態是 Debug 與有指定相關模擬器,此就可以按下 F5 開始執行 Android的除錯組態與指定模擬器
  3. 執行結果畫面
    使用者登入畫面1
    按下了 登入 按鈕,就會進入到首頁
    使用者登入畫面2

iOS 系統

  1. 請使用滑鼠右擊方案總管內的 XamarinLogin.iOS 專案節點,選擇 設定為起始專案 項目。
  2. 確認建置組態是 Debug 與有指定相關模擬器,此就可以按下 F5 開始執行 iOS的除錯組態與指定模擬器
  3. 執行結果畫面
    iOS使用者登入畫面1
    按下了 登入 按鈕,就會進入到首頁
    iOS使用者登入畫面2

存在問題

當在 Android 平台上,進入到應用首頁頁面之後,若點擊了左上角的 應用首頁 文字旁的箭頭,則,這個應用程式會回到 使用者登入 的頁面中。
當在 iOS 平台上,進入到應用首頁頁面之後,若點擊了左上角的 回到登入頁面 區域,則,這個應用程式會回到 使用者登入 的頁面中。
這樣的操作流程,當然是不正確的,因為,一旦使用者登入進系統之後,除非選擇了登出作業,否則,應該是不能夠再度使用螢幕上的返回按鈕,或者手機的實體返回按鈕,讓這個應用程式,回到登入頁面上。因此,接下來,就來修正此一問題,當使用者成功能入之後,接著切換到應用程式首頁內,要清除INavigation.NavigationStack 內的登入頁面資料,這樣,使用者就無法透過螢幕按鈕或者手機實體按鈕,再度回到 登入頁面了。

修正登入成功後,無法回到登入頁面

切換到首頁時候,清空導航堆疊

打開 核心PCL 專案內的 LoginPage.xaml.cs 檔案,新增一個方法 ClearStackTo(),並且在按鈕點擊事件內,當切換到應用首頁頁面之後,呼叫這個方法。
這個方法 ClearStackTo() 運作原理相當的簡單,那就是,它會嘗試移除任何在 NavigationStack 內的任何頁面,只會保留最後一個。要移除 NavigationStack 內的項目,使用了 Navigation.RemovePage(page);方法,進行移除 NavigationStack 內的項目。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace XamarinLogin
{
    public partial class LoginPage : ContentPage
    {
        public LoginPage()
        {
            InitializeComponent();

            NavigationPage.SetBackButtonTitle(this, "回登入頁面");
            buttonLogin.Clicked += ButtonLogin_Clicked;
        }

        private async void ButtonLogin_Clicked(object sender, EventArgs e)
        {
            // 切換到主頁面
            var NextPage = new MainPage();

            await Navigation.PushAsync(NextPage);
            ClearStackTo();
        }

        private void ClearStackTo()
        {
            var stack = Navigation.NavigationStack;

            while (stack.Count > 1)
            {
                var page = stack.First();
                if (page != null)
                {
                    Navigation.RemovePage(page);
                }
                else
                {
                    break;
                }
            }
        }
    }
}
接著,打開 MainPage.xaml.cs 檔案,將內容修正如下所示:
其中,在建構式內,加入此方法呼叫 NavigationPage.SetHasBackButton ,目的在於要將回上一頁按鈕隱藏起來。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XamarinLogin
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            NavigationPage.SetHasBackButton(this, false);
            NavigationPage.SetBackButtonTitle(this, "回到首頁");
        }
    }
}

執行結果

Android 系統

  1. 請使用滑鼠右擊方案總管內的 XamarinLogin.Droid 專案節點,選擇 設定為起始專案 項目。
  2. 確認建置組態是 Debug 與有指定相關模擬器,此就可以按下 F5 開始執行 Android的除錯組態與指定模擬器
  3. 執行結果畫面
    使用者登入畫面1
    按下了 登入 按鈕,就會進入到首頁
    使用者登入畫面4

iOS 系統

  1. 請使用滑鼠右擊方案總管內的 XamarinLogin.iOS 專案節點,選擇 設定為起始專案 項目。
  2. 確認建置組態是 Debug 與有指定相關模擬器,此就可以按下 F5 開始執行 iOS的除錯組態與指定模擬器
  3. 執行結果畫面
    iOS使用者登入畫面1
    按下了 登入 按鈕,就會進入到首頁
    iOS使用者登入畫面4

進階應用 Font Awesome

底下的步驟,將會分別說明如何設定 Android 與 iOS 類型專案,使其可以使用 Font Awesome 字體圖示。並且也會修正登入頁面,在 XAML 宣告定義中,使用 Font Awesome字體圖示。

下載 Font Awesome 字型檔案與安裝

先打開瀏覽器,進入到 Font Awesome 官網 http://fontawesome.io/,在官網首頁,會看到下載連結,點擊該連結,下載 Font Awesome的壓縮檔案。
打開 Font Awesome 壓縮檔案後,將內容解壓縮到您的硬碟上,請將底下範例圖片中的 font-awesome-4.6.3\fonts\fontawesome-webfont.ttf 檔案,改名成為 font-awesome-4.6.3\fonts\fontawesome.ttf (之後通稱這個檔案為 fontawesome.ttf )
Font Awesome壓縮檔內容
使用檔案總管,將這個 fontawesome.ttf 檔案,拖拉到 XamarinLogin.Droid 專案內的 Assets 資料夾內。
fontawesome.ttf在Assets內
使用檔案總管,將這個 fontawesome.ttf 檔案,拖拉到 XamarinLogin.iOS 專案內的 Resources 資料夾內。
fontawesome.ttf在Resources內
想要在 Android 與 iOS 系統內使用 Font Awesome 提供的字體圖示,做法並不一樣,底下分別就兩個平台的做法進行說明。

修正 核心PCL 的登入頁面

在 核心PCL 專案內,開啟 LoginPage.xaml 檔案,將這個檔案的 XAML 定義修改成如下定義。
這個新修訂的 LoginPage.xaml 檔案,將 Grid 修改成為二維的網格狀,因為,需要在第一個 Column 中,放置 Font Awesome 的字型圖示。
當要顯示 Font Awesome 字型圖示,只需要將要顯示的 Font Awesome 相對應的 Unicode 碼,寫道Label.Text 內,如下列範例所示。不過,為了要能夠讓不同平台可以顯這這個 Font Awesome 字型圖示,建議也要加入這個定義 FontFamily="FontAwesome"
<Label Text="&#xf007;"
           FontSize="25"
           FontFamily="FontAwesome"
           Grid.Row="1" Grid.Column="0"
           />
LoginPage.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="XamarinLogin.LoginPage"
             Title="使用者登入"
             >

  <Grid
    HorizontalOptions="FillAndExpand" VerticalOptions="Center"
    Padding="30,0"
      >
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="30" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Label Text="歡迎來到 Xamarin.Forms"
           FontSize="40"
           Grid.Row="0" Grid.ColumnSpan="2"
           HorizontalTextAlignment="Center"
           />
    <Label Text="&#xf007;"
           FontSize="25"
           FontFamily="FontAwesome"
           Grid.Row="1" Grid.Column="0"
           />
    <Entry Placeholder="請輸入帳號"
           x:Name="entryAccount"
           Grid.Row="1" Grid.Column="1"
           HorizontalOptions="FillAndExpand"
             />
    <Label Text="&#xf084;"
           FontSize="25"
           FontFamily="FontAwesome"
           Grid.Row="2" Grid.Column="0"/>
    <Entry Placeholder="請輸入密碼"
           x:Name="entryPassword"
           Grid.Row="2" Grid.Column="1"
           IsPassword="True"  />
    <Button Text="登入"
            x:Name="buttonLogin"
            Grid.Row="3" Grid.ColumnSpan="2"
            HorizontalOptions="FillAndExpand"
              />
  </Grid>
</ContentPage>

Android 專案部分

請在 XamarinLogin.Droid 專案內,建立一個名為 Renderers 資料夾,並且在此資料夾內,建立一個類別檔案 AwesomeRenderer.cs。該類別檔案的內容如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using Android.Graphics;
using XamarinLogin.Droid.Renderers;

[assembly: ExportRenderer(typeof(Label), typeof(AwesomeLabelRenderer))]
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(AwesomeButtonRenderer))]
namespace XamarinLogin.Droid.Renderers
{
    public class AwesomeLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            AwesomeUtil.CheckAndSetTypeFace(Control);
        }
    }

    public class AwesomeButtonRenderer : ButtonRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);

            AwesomeUtil.CheckAndSetTypeFace(Control);
        }
    }

    internal static class AwesomeUtil
    {
        public static void CheckAndSetTypeFace(TextView view)
        {
            if (view.Text.Length == 0) return;
            var text = view.Text;
            if (text.Length > 1 || text[0] < 0xf000)
            {
                return;
            }

            var font = Typeface.CreateFromAsset(Xamarin.Forms.Forms.Context.ApplicationContext.Assets, "fontawesome.ttf");
            view.Typeface = font;
        }
    }
}

iOS 專案部分

在 XamarinLogin.iOS 專案中,使用滑鼠右擊 Info.plist 檔案,在彈出功能表中,選擇 開啟方式,再出現 開啟方式 - Info.plist 對話窗後,請選擇 XML(文字)編輯器,接著,點擊 確定 按鈕。
此時,Visual Studio 會開啟 XML 編輯器,請參考下兩圖,加入底下 XML 宣告到 Info.plist 檔案內。
    <key>UIAppFonts</key>
    <array>
      <string>fontawesome.ttf</string>
    </array>  </dict>
  • Info.plist尚未修改前的內容截圖
    Info.plist尚未修改前
  • Info.plist尚未修改後的內容截圖
    Info.plist尚未修改後

Font Awesome 的執行結果

底下分別展示出這兩個平台的執行成果。

Android 專案執行成果

fontawesome-Android

iOS 專案執行成果

fontawesome-iOS