XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/07/13

Xamarin.Forms 平台特色

平台特色

在進行 Xamarin.Forms 跨平台應用程式開發的時候,由於,開發者會將大部分的商業邏輯與視覺介面都在核心PCL內進行開發,不過,有些時候在共用的商業邏輯程式碼內或者在共用視覺介面 XAML 定義宣告中,想是根據不同的平台與系統做出不同的反映;這樣的需求,就是這個章節存在的目的。
在這個章節內,開發者可以在核心PCL專案內,
  • 得知使用者當時的裝置是 手機或平板或桌機 (使用 Device.Idiom)
  • 依據使用者當時裝置的作業系統是 iOS/Android/WinPhone/Windows (使用 Device.OS)
  • 在撰寫 XAML 內容時候,需要能夠針對不同的平台,提供不同的視覺效果 (使用 Device.OnPlatform)`
  • 需要能夠使用類似 C# Timer 定時器方法功能,Device.StartTimer)
  • 最後,類似 WPF 開發方式,對於背景執行非同步執行續,有部分程式碼有更新UI內容,這個時候就可以使用 Device.BeginInvokeOnMainThread

建立標籤式的樣板式頁面方案

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

MainPage

  • 首先,打開核心PCL 的 MainPage.xaml 檔案,將底下的 XAML 宣告定義複製到這個檔案內。
  • 在應用程式的首頁頁面, 首先使用了 ContentPage.Padding 來定義整個頁面的 Padding 範圍,會要這樣做的原因是,若 Xamarin.Forms 的 ContentPage 在 iOS 平台下執行的話,他會與最上方的狀態列互相重疊,如下圖所示,因此,需要特別針對 iOS 平台進行調整,避免發生這樣的情況。
    解決方案就是定義 ContentPage.Padding,在其裡面使用 OnPlatform x:TypeArguments="Thickness"分別指定個平台所需要的 Thickness 的值。
    iOS_XFDevice1
  • 這個頁面的控制項,使用了 Grid 版面配置來進行所有控制項的定位。
  • 在這個 XAML 範例內,關於 <OnPlatform ...> ... </<OnPlatform> 的使用方式,提供了不同的寫法,不論哪種用法,都具有同樣的效果。
  • 當在 OnPlatform 內,使用了 x:TypeArguments 指定所要客製化的物件值;若所要指定的物件屬於C#的基本型別,此時,您需要使用 XAML 標記延伸功能,使用 x:來指明所要設定的資料型別。

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"
             xmlns:local="clr-namespace:XFDevice"
             x:Class="XFDevice.MainPage"
             Title="知道我在哪個平台上嗎?"
             >
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness">
      <OnPlatform.iOS>
        0,20,0,0
      </OnPlatform.iOS>
      <OnPlatform.Android>
        0, 0, 0, 0
      </OnPlatform.Android>
      <OnPlatform.WinPhone>
        0, 0, 0, 0
      </OnPlatform.WinPhone>
    </OnPlatform>
  </ContentPage.Padding>

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

    <Label
      Grid.Row="0" Grid.Column="0">
      <Label.Text>
        <OnPlatform x:TypeArguments="x:String">
          <OnPlatform.iOS>我正在使用 iOS</OnPlatform.iOS>
          <OnPlatform.Android>我正在使用 Android</OnPlatform.Android>
          <OnPlatform.WinPhone>我正在使用 WinPhone</OnPlatform.WinPhone>
        </OnPlatform>

      </Label.Text>
    </Label>

    <BoxView
      Grid.Row="0" Grid.Column="1"
      HorizontalOptions="Center" VerticalOptions="Center"
      >
      <BoxView.BackgroundColor>
        <OnPlatform x:TypeArguments="Color"
          iOS="Green"
          Android="#738182"
          WinPhone="Accent"
        />
      </BoxView.BackgroundColor>
      <BoxView.WidthRequest>
        <OnPlatform x:TypeArguments="x:Double"
          iOS="130"
          Android="80"
          WinPhone="30" />
      </BoxView.WidthRequest>
      <BoxView.HeightRequest>
        <OnPlatform x:TypeArguments="x:Double"
          iOS="130"
          Android="80"
          WinPhone="30" />
      </BoxView.HeightRequest>
    </BoxView>

    <Label
      x:Name="label處理中"
      Text="處理中"
      HorizontalOptions="Center" VerticalOptions="Center"
      Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
      />

    <Button
      x:Name="button猜猜我是誰"
      Text="猜猜我是誰"
      HorizontalOptions="Center" VerticalOptions="Center"
      Grid.Row="2" Grid.Column="0"
      Clicked="OnGuessClicked" />

    <Button
      x:Name="button定時更新"
      Text="定時更新"
      Grid.Row="2" Grid.Column="1"
      Clicked="OnTimerClicked" />

     <Button
      x:Name="button背景處理中"
      Text="背景處理中"
      Grid.Row="3" Grid.Column="0"
      Clicked="OnBackgroundClicked" />

   <Button
      x:Name="button開啟網頁"
      Text="開啟網頁"
      Grid.Row="3" Grid.Column="1"
      Clicked="OnOpenUriClicked" />

  </Grid>

</ContentPage>
在 MainPage.xaml 的 code-behind 裡面,有定義了相關事件處理用法。
  • 若想要在 C# 中針對不同平台執行不同的程式碼,此時,可以使用 Device.OnPlatform 這個方法,例如,在 OnGuessClicked 按鈕事件方法內,根據不同作業系統與是否為平板或手機,傳回不同的字串,並且顯示在螢幕畫面上。
  • 在核心PCL專案內,若想要使用 C# 的定時器功能 Timer, DispatcherTimer 這類功能,可以使用Device.StartTimer 這個方法來取代;在這個方法內,若想要繼續下一個週期的定時執行,請回傳true,若想要停止週期定時執行,請回傳 false
  • 最後,在 OnBackgroundClicked 這個事件處理方法內,說明了,當使用了非同步的背景執行時候,在背景運行程式碼內,想要更新 UI 內容的時候,您需要透過 Device.BeginInvokeOnMainThread 這個方法,讓您相關更新 UI 內容的程式碼,在 UI 執行續內來執行。

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace XFDevice
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

        }

        void OnGuessClicked(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            Device.OnPlatform(
                iOS: ()=>
                {
                    sb.Append("嗯嗯嗯,您是 iOS, ");
                },
                Android: () =>
                {
                    sb.Append("嗯嗯嗯,您是 Android, ");
                },
                WinPhone: () =>
                {
                    sb.Append("嗯嗯嗯,您是 WinPhone, ");
                }
                );
            sb.Append(Device.Idiom.ToString());

            button猜猜我是誰.Text = sb.ToString();
        }

        void OnTimerClicked(object sender, EventArgs e)
        {
            int fooCC = 0;
            int fooMax = 50;
            Device.StartTimer(new TimeSpan(0, 0, 1), () => {

                button定時更新.Text = $"{DateTime.Now}";

                if (++fooCC > fooMax)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            });
        }

        void OnBackgroundClicked(object sender, EventArgs e)
        {
            Task.Factory.StartNew(()=>
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    label處理中.Text = $"處理中 現在時間:{DateTime.Now}";
                });
            });
        }

        void OnOpenUriClicked(object sender, EventArgs e)
        {
            Device.OpenUri(new Uri("http://www.xamarin.com"));
        }
    }
}

實際執行畫面

請再度重新執行,這個時候應用程式可以順利正常運行,螢幕截圖如下:
And_XFDevice

佈署注意事項

iOS 執行結果

請在方案總管內,滑鼠右擊 XFDevice.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
iOS_XFDevice

佈署注意事項

參考

2016/07/12

Xamarin.Forms 解決 VS Emulator for Android無法接收推播

解決 VS Emulator for Android無法接收推播

當您正在開發 Xamarin.Forms for Android 應用程式,並且,選擇使用 Visual Studio Emulator for Android 模擬器做為開發測試之用;不過,當您想要開發與測試 Google Map、接收推播等等功能的時候,卻發現到應用程式執行的時候,會發生例外異常訊息如下圖:
沒有Google Play Services的錯誤訊息
會發生這樣的情況,這是因為 Visual Studio Emulator for Android 模擬器內沒有安裝 Google Play Services(因為使用授權上的問題),因此,您只需要把 Google Play Services 安裝到 Visual Studio Emulator for Android 模擬器上,一切的問題就解決了。

下載 Google Play Services 安裝套件

  1. 請到 Team Android (http://teamandroid.com/gapps) 這個網站來下載 Goo Apps 套件
  2. 確認要下載的 符合您模擬器的裝置設定檔之Android 版本,在這個範例中所使用的 Android 模擬器版本為 4.4.4 (可以在模擬器中點選 Settings > SYSTEM > About phone 便可以查詢到,如下圖)。
    模擬器的Android版本
    因此,在 Team Android 網頁內,找到 Android 4.4 - KitKat 這個區段,下載 gapps-kk-20140105-signed.zip 這個檔案。
    Android4.4
  3. 拖拉檔案 gapps-kk-20140105-signed.zip 到您正在使用的 Visual Studio Emulator for Android 模擬器上,當您在模擬器上放開之後,會出現下圖警告對話窗,請點選 Install and shut down 這個按鈕。
    InstallToVSEmulator
  4. 此時,安裝程式會進行把 Google Play Services 安裝到模擬器內。當出現底下對話窗,則表示已經安裝完成,請點選 OK 按鈕,接著,模擬器會自動關閉。
    InstallingToVSEmulator
    InstallToVSEmulatorComplete
  5. 接著,需要啟動 Visual Studio Emulator for Android 模擬器,看看是否 Google Play Store 已經安裝完成了;請在 Visual Studio 2015 功能表點選 工具 > Visual Studio Emulator for Android,當出現 Visual Studio Emulator for Android 對話視窗後,選擇您需要的模擬器,在這裡,選擇的是 4.7" KitKat (4.4) XHDPI Phone API Level 19,這個模擬器,在這個項目的右方,有個綠色三角形,點選這個按鈕,就會啟動這個模擬器了。
    Visual Studio Emulator for Android
  6. 當模擬器重新開啟完成後,打開程式清單,若有看到 Play Store 圖示,那就表示 Google Play Store已經安裝完成了。
    PlayStoreInstalled

參考

Xamarin.Forms 建置 Android 專案,發生 java.lang.OutOfMemoryError 錯誤

建置 Android 專案,發生 java.lang.OutOfMemoryError 錯誤

有時候,當建置 Xamarin.Android 專案的時候,只有發現一個錯誤,那就是java.lang.OutOfMemoryError, 可是,整個專案都檢查過了,沒有任何問題,此時,請參考這篇文章,進行問題修復。
嚴重性 程式碼 說明 專案 檔案 行 隱藏項目狀態 錯誤 java.lang.OutOfMemoryError. Consider increasing the value of $(JavaMaximumHeapSize). Java ran out of memory while executing 'java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools\23.0.1\lib\dx.jar" --no-strict --dex --output=obj\Debug\android\bin obj\Debug\android\bin\classes "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v5.0\mono.android.jar" obj\Debug_libraryprojects\FormsViewGroup\library_project_imports\formsviewgroup.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.Animated.Vector.Drawable\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.Design\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v4\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v4\23.3.0.0\embedded\libs\internal_impl-23.3.0.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v7.AppCompat\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v7.CardView\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v7.MediaRouter\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v7.MediaRouter\23.3.0.0\embedded\libs\internal_impl-23.3.0.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.v7.RecyclerView\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.Android.Support.Vector.Drawable\23.3.0.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.GooglePlayServices.AppIndexing\8.4.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.GooglePlayServices.Base\8.4.0\embedded\classes.jar C:\Users\vulca\AppData\Local\Xamarin\Xamarin.GooglePlayServices.Basement\8.4.0\embedded\classes.jar' WorkingWithGestures.Android
java.lang.OutOfMemoryError

解決方式

請使用滑鼠右擊 Android 專案,點選 屬性 項目,當出現該專案的屬性標籤頁次,請接著點選 Android Options > Advanced,此時,您會看到 Advanced Android Build Settings 這個項目裡有個 Java Max Heap Size,請在該項目的底下文字輸入盒輸入 1G。並且,請重新編一看看,您的問題應該就已經解決了。
Android專案屬性JavaMaxHeap

Xamarin.Forms 進階應用 Font Awesome

進階應用 Font Awesome

對於想要在 Xamarin.Forms 專案內,想要用 Font Awesome 字體,您需要分別設定 Android 與 iOS 類型專案,使其可以使用 Font Awesome 字體圖示。

下載 Font Awesome 字型檔案與安裝

先打開瀏覽器,連線https://github.com/vulcanlee/Xamarin.Forms.StepByStep/tree/master/Font%20Awesome 會看到 Font Awesome 字型檔案 fontawesome.ttf ,點擊該連結,下載 Font Awesome的檔案到您本機磁碟機某個目錄上。
使用檔案總管,將剛剛下載的這個 fontawesome.ttf 檔案,拖拉到 Android 專案內的 Assets 資料夾內。
fontawesome.ttf在Assets內
使用檔案總管,將這個 fontawesome.ttf 檔案,拖拉到 iOS 專案內的 Resources 資料夾內。
fontawesome.ttf在Resources內

原生專案的修正

想要在 Android 與 iOS 系統內使用 Font Awesome 提供的字體圖示,做法並不一樣,底下分別就兩個平台的做法進行說明。

Android 專案部分

請在 Android 專案內,建立一個名為 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 XFGestures.Droid;
using Android.Graphics;
using XFGestures.Droid.Renders;

[assembly: ExportRenderer(typeof(Label), typeof(AwesomeLabelRenderer))]
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(AwesomeButtonRenderer))]
namespace XFGestures.Droid.Renders
{
    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 專案部分

在 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

在 XAML 內

  • 請使用 Label 控制項,並且在 Text 屬性上使用 &#xf000; 這樣的表示式這個圖示字體http://fontawesome.io/icon/glass/
  • 另外,請使用 FontFamily="FontAwesome" 來表示需要使用 Font Awesome 的圖示字體
<Label Text="&#xf000;"
           FontSize="60"
           FontFamily="FontAwesome"
           Margin="0,0,40,0"
           />

在 C# 內

string FAGlass = "\uf000";

如何查詢有哪些可用的 Font Awesome 圖示字體