XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/08/22

在 Xamarin.Forms 使用 Font Awesome 的方法歸納

在 Xamarin.Forms 使用 Font Awesome 的方法歸納

要在 Xamarin.Forms 使用 Font Awesome,有兩種做法
  • 針對 Label 使用 ExportRenderer
  • 客製化一個 Label,並且使用 ExportRenderer
這份筆記的範例專案可以從此下載

Font Awesome 檔案準備

先打開瀏覽器,連線https://github.com/vulcanlee/Xamarin.Forms.StepByStep/tree/master/Font%20Awesome 會看到 Font Awesome 字型檔案 fontawesome.ttf ,點擊該連結,下載 Font Awesome的檔案到您本機磁碟機某個目錄上。

Android

使用檔案總管,將剛剛下載的這個 fontawesome.ttf 檔案,拖拉到 Android 專案內的 Assets 資料夾內。

iOS

使用檔案總管,將剛剛下載的這個 fontawesome.ttf 檔案,拖拉到 iOS 專案內的 Resources 資料夾內。

UWP

使用檔案總管,將剛剛下載的這個 fontawesome.ttf 檔案,拖拉到 UWP 專案內的 Assets/Fonts 資料夾內。
若 Fonts 資料夾不存在,請在 Visual Studio 建立此資料夾

各原生平台修正

Android 的修正

  1. 在 Android 原生專案內,建立資料夾 Renderers
  2. 建立 AwesomeRenderer 類別,程式碼如下

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;
using XFSplash.Droid.Renderers;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;

[assembly: ExportRenderer(typeof(Label), typeof(AwesomeLabelRenderer))]
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(AwesomeButtonRenderer))]
namespace XFSplash.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;
        }
    }
}
  1. 建立 FontAwesomeLabelRenderer 類別,程式碼如下
    若使用這個方法,您需要在核心 PCL 專案內建立一個類別 FontAwesomeLabel

FontAwesomeLabelRenderer.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;
using XFSplash.Droid.Renderers;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;
using XFSplash.Renderers;

[assembly: ExportRenderer(typeof(FontAwesomeLabel), typeof(FontAwesomeLabelRenderer))]
namespace XFSplash.Droid.Renderers
{
    class FontAwesomeLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);
            var label = Control;
            Typeface font;
            try
            {
                font = Typeface.CreateFromAsset(Forms.Context.Assets, "fontawesome.ttf");
                label.Typeface = font;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("TTF file not found. Make sure the Android project contains it at 'fontawesome.ttf'.");
            }

        }
    }
}
``
### FontAwesomeLabel.cs

這個類別請在核心PCL專案內建立

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

namespace XFSplash.Renderers
{
    public class FontAwesomeLabel : Label
    {
        public FontAwesomeLabel()
        {
            FontFamily = Device.OnPlatform("fontawesome", "fontawesome", "/Assets/Fonts/fontawesome.ttf#FontAwesome");
        }
    }
}

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尚未修改後

UWP 的修正

如何使用 Font Awesome

在核心PCL專案的 XAML 內,使用底下宣告,就可以使用 Font Awesome 字體
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             xmlns:Renderers="clr-namespace:XFSplash.Renderers;assembly=XFSplash"
             x:Class="XFSplash.Views.MainPage"
             Title="MainPage">

  <ContentPage.Resources>
    <ResourceDictionary>
      <OnPlatform x:Key="FontAwesome"
               x:TypeArguments="x:String"
               iOS="fontawesome"
               Android="fontawesome"
               WinPhone="/Assets/Fonts/fontawesome.ttf#FontAwesome" />
    </ResourceDictionary>
  </ContentPage.Resources>
  <Grid>
    <Image
      Aspect="AspectFill"
      >
      <Image.Source>
        <OnPlatform
          x:TypeArguments="ImageSource"
          iOS="MainPageImg.jpg"
          Android="MainPageImg.jpg"
          WinPhone="Assets/MainPageImg.jpg"
          />
      </Image.Source>
    </Image>

    <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
      <Label Text="{Binding Title}" FontSize="30"
             HorizontalTextAlignment="Center"
             TextColor="#a64dff"
             />
      <StackLayout
        Orientation="Horizontal"
        HorizontalOptions="Center"
        >
        <Renderers:FontAwesomeLabel Text="&#xf164;"
             TextColor="#ff3333"
             HorizontalOptions="Center"
             FontSize="60"
             Margin="0,0,20,0"
           />
        <Label Text="&#xf164;"
               TextColor="#ff3333"
               HorizontalOptions="Center"
               FontSize="60"
               Margin="0,0,20,0"
          >
          <Label.FontFamily>
            <OnPlatform
            x:TypeArguments="x:String"
            iOS="fontawesome"
            Android="fontawesome"
            WinPhone="/Assets/Fonts/fontawesome.ttf#FontAwesome"
          />
          </Label.FontFamily>
        </Label>
        <Label Text="&#xf164;"
             TextColor="#ff3333"
             HorizontalOptions="Center"
             FontSize="60"
             FontFamily="{StaticResource FontAwesome}"
             Margin="0,0,20,0"
          />
      </StackLayout>

    </StackLayout>
  </Grid>
</ContentPage>

2016/08/20

Microsoft.VisualStudio.WinRT.TemplateWizards.ApplicationInsights.Wizard’ 不存在的問題解法

若您在升級到 Visual Studio 2015 Update 3 後,發現到無法建立一個 Universal Windows 類型專案,出現了底下錯誤訊息
vstemplate 檔案參考了不在
‘Microsoft.VisualStudio.WinRT.TemplateWizards, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ 組件中的精靈類別. ‘Microsoft.VisualStudio.WinRT.TemplateWizards.ApplicationInsights.Wizard’, which does not exist in the assembly
The vstemplate file references the wizard class ‘Microsoft.VisualStudio.WinRT.TemplateWizards.ApplicationInsights.Wizard’, which does not exist in the assembly ‘Microsoft.VisualStudio.WinRT.TemplateWizards, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.
請到這個目錄下
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ProjectTemplates\CSharp\Windows Root\Windows UAP\1033\BlankApplication\BlankApplication.vstemplate
移除底下資訊,就會恢復正常了
  <WizardExtension>
    <Assembly>Microsoft.VisualStudio.WinRT.TemplateWizards, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
    <FullClassName>Microsoft.VisualStudio.WinRT.TemplateWizards.ApplicationInsights.Wizard</FullClassName>
  </WizardExtension>
底下的方法都無效
可以參考這篇文章的作法 (Er Naparan)
enter image description here
您需要重新執行一次 Visual Studio 安裝程式,接著選擇 Modify > 功能 > Windows 及 Web 程式開發 > 通用 Windows 應用程式開發工具 > 全選後,按下 更新
enter image description here
https://blogs.msdn.microsoft.com/visualstudio/2016/06/07/visual-studio-2015-update-3-rc/

Windows UWP 客製照相功能

Windows UWP 客製照相功能

由於最近專案會需要用到在 Windows Mobile 10 手機上,針對鏡頭可以進行各項拍照功能微調,因此,根據研究與相關資料,將手機拍照功能整理出這份文件。

關於應用程式生命週期管理

  1. 在進入到特定頁面,該頁面要顯示手機鏡頭的預覽畫面的時候,需要根據Windows UWP 的應用程式生命週期,訂閱 Application.Current.Suspending & Application.Current.Resuming 這兩個事件,在前者,您需要將拍照鏡頭的資源予以釋放,而在後者,需要取得拍照功能的資源。
  2. 您可以使用 DeviceInformation.FindAllAsync(DeviceClass.VideoCapture)方法,取得裝置上的所有鏡頭裝置,並且針對前鏡頭或者後鏡頭進行處理。
  3. 建立 MediaCapture類別物件與MediaCaptureInitializationSettings類別物件,準備根據不同的條件,調整鏡頭拍照的參數。例如,可以使用這個方法,await _mediaCapture.InitializeAsync(settings);進行拍照裝置的初始化。
  4. 關於 MediaCapture類別說明文件與MediaCaptureInitializationSettings類別說明文件,可以分別參考 MediaCapture & MediaCaptureInitializationSettings
  5. 透過 MediaCapture.VideoDeviceController 取得的物件,其類型為 VideoDeviceController,可用於控制拍照裝置的各種行為,參考文件為 VideoDeviceController
    • BacklightCompensation
      提供取得和設定背光補償之方法, 如果值為 1,則啟用背光補償。如果值為 0,則停用背光補償
    • Brightness
      提供用於獲取和設置明亮度方法
    • Contrast
      提供用於獲取和設置對比度方法
    • Exposure
      提供用於獲取和設置曝光時間的方法
    • FlashControl
      拍照設備的閃光控制。FlashControl類別 具有下列類型的成員 Auto / Enabled / PowerPercent / PowerSupported / RedEyeReduction / RedEyeReductionSupported / Supported
    • Focus
      提供方法來獲取和設置焦點
    • Hue
      Gets or sets the camera’s hue setting
    • IsoSpeedControl
      Gets the ISO film speed control for this video device
    • LowLagPhoto
      Gets the low shutter lag photo control for this video device
    • LowLagPhotoSequence
      Gets the low shutter lag photo sequence control for this video device
    • Pan
      獲取或設置相機的Pan
    • PrimaryUse
      獲取或設置該主要使用設備
    • RegionsOfInterestControl
      此視頻的設備獲取利益控制的區域
    • Roll
      獲取或設置相機的膠卷(設置
    • SceneModeControl
      此視頻的設備獲取場景模式控制
    • Tilt
      獲取或設置相機的移軸模式設置
    • TorchControl
      獲取此視頻設備的亮燈手電筒模式控制
    • WhiteBalance
      獲取或設置在相機的白平衡
    • WhiteBalanceControl
      獲取此視頻設備的白平衡控制
    • Zoom
      獲取和設置相機的放大與縮小

其他參考

Universal Windows 10 SDK: Adding GPS to the Camera Sample

2016/08/19

Xamarin.Forms 警告與動作表對話窗

Xamarin.Forms 警告與動作表對話窗

這份筆將將會整理出 警告 Alert 對話窗與 動作表 Action Sheet 對話窗的使用;由於 Xamarin.Forms 提供了這兩種方法的使用 ( DisplayAlert / DisplayActionSheet ),不過,這兩種方法卻是定義在 Page 類別中,因此,這兩個方法僅能夠在程式碼後置 (code-behind) 的地方使用。
若您是採用了 Prism 的框架來進行開發 Xamarin.Forms 應用程式,根據 MVVM 的規範,您應該要在 檢視模型(ViewModel) 內來使用兩個方法,而在檢視模型內,因為 MVVM 的規範,是無法存取到 檢視 內的物件(當然,也是有辦法的,不過,有點違反 MVVM 設計模式了),因此,Prism 提供了 IPageDialogService 介面,您可以在建構式內注入這個介面,並取得其執行個體(Instance),就可以透過這個執行個體進行這兩個對話窗的操作了。
這份筆記的範例專案可以底下網址取得

傳統的 Xamarin.Forms 的用法

  1. 在範例專案中的 檢視(View),定義了這個應用程式所有的使用者介面,其 XAML 宣告如下,而這個範例的執行畫面也如下圖。
    XFandPrismAlert
    XFandPrismAlert
    XFandPrismAlert
    XFandPrismAlert
  2. 這個頁面中,定義了四個按鈕與四個標籤(Label),前兩個按鈕的按下事件將會定義在 code-behind 程式碼內,後兩個按鈕的按下事件,將會透過 ICommand 資料繫結到 檢視模型內的 DelegateCommand 物件。
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFAlert.Views.MainPage"
             Title="MainPage">
  <StackLayout
    HorizontalOptions="Center" VerticalOptions="Center">
    <Button
      x:Name="btnAlert"
      Text="顯示 Xamarin.Forms 警告視窗"
      />
    <Label
      x:Name="lblXF選擇結果"
      Text="Xamarin.Forms 選擇結果"
      />
    <Button
      x:Name="btnActionSheet"
      Text="顯示 Xamarin.Forms 動作表單"
      />
     <Label
      x:Name="lblXF動作表單選擇結果"
      Text="Xamarin.Forms 動作表單 選擇結果"
      />
    <Button
      Text="顯示 Prism 警告視窗"
      Command="{Binding PrismAlertCommand}"
      />
    <Label
      Text="{Binding PrismAlert輸出結果}"
      />
    <Button
      Text="顯示 Prism 動作表單"
      Command="{Binding PrismActionSheetCommand}"
      />
    <Label
      Text="{Binding PrismActionSheet輸出結果}"
      />
 </StackLayout>
</ContentPage>
  1. MainPage.xaml 的 code-behind 定義如下:
  2. btnAlert.Clicked 事件展示了 DisplayAlert 的用法
  3. btnActionSheet.Clicked 事件展示了 DisplayActionSheet 的用法
using Xamarin.Forms;

namespace XFAlert.Views
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            btnAlert.Clicked += async (s, e) =>
              {
                  await DisplayAlert("警告", "您確定要繼續執行嗎?", "確定");
                  bool 選擇結果 = await DisplayAlert("通知", "您要開始下載這個檔案嗎?", "是", "否");
                  lblXF選擇結果.Text = 選擇結果.ToString();
              };
            btnActionSheet.Clicked += async (s, e) =>
              {
                  var 選擇結果 = await DisplayActionSheet("請選擇您要分享的目的應用程式?", "取消", "Google+", "Email", "Twitter", "Facebook");
                  lblXF動作表單選擇結果.Text = 選擇結果;
              };
        }

    }
}

Prism 提供的功能

  1. 底下為 MainPage 的檢視模型程式碼
  2. Prism 提供了 IPageDialogService 頁面,讓您可以使用者兩個對話窗功能,因此,您需要透過建構式注入的方法,取得這個介面的執行個體。
  3. 您也需要定義兩個 DelegateCommand 屬性,用於資料繫結到 XAML 上的 Button.Command 屬性上。
  4. 另外,也定義了兩個 string 的屬性,並且要實作出 INotifyPropertyChanged 介面的功能,在這裡使用的是 SetProperty
  5. 不論是使用 Xamarin.Forms 提供的方法或者 Prism 提供的方法,都需要使用非同步的方式來呼叫。
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Services;
using System;
using System.Collections.Generic;
using System.Linq;

namespace XFAlert.ViewModels
{
    public class MainPageViewModel : BindableBase, INavigationAware
    {
        public IPageDialogService _dialogService { get; set; }
        public DelegateCommand PrismAlertCommand { get; set; }
        public DelegateCommand PrismActionSheetCommand { get; set; }

        #region PrismAlert輸出結果
        private string _PrismAlert輸出結果;
        public string PrismAlert輸出結果
        {
            get { return _PrismAlert輸出結果; }
            set { SetProperty(ref _PrismAlert輸出結果, value); }
        }
        #endregion

        #region PrismActionSheet輸出結果
        private string _PrismActionSheet輸出結果;
        public string PrismActionSheet輸出結果
        {
            get { return _PrismActionSheet輸出結果; }
            set { SetProperty(ref _PrismActionSheet輸出結果, value); }
        }
        #endregion

        public MainPageViewModel(IPageDialogService dialogService)
        {
            _dialogService = dialogService;

            PrismAlertCommand = new DelegateCommand(PrismAlert);
            PrismActionSheetCommand = new DelegateCommand(PrismActionSheet);

            PrismAlert輸出結果 = "Prism 選擇結果";
            PrismActionSheet輸出結果 = "Prism 動作表單 選擇結果";
        }

        private async void PrismAlert()
        {
            await _dialogService.DisplayAlertAsync("警告", "您確定要繼續執行嗎?", "確定");
            bool 選擇結果 =await _dialogService.DisplayAlertAsync("通知", "您要開始下載這個檔案嗎?", "是", "否");
            PrismAlert輸出結果 = 選擇結果.ToString();
        }

        private async void PrismActionSheet()
        {
            var 選擇結果 = await _dialogService.DisplayActionSheetAsync("請選擇您要分享的目的應用程式?", "取消", "Google+", "Email", "Twitter", "Facebook");
            PrismActionSheet輸出結果 = 選擇結果;
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {
        }
    }
}