萬年曆與QR-Code 條碼
在這個範例專案中,將會實作出 萬年曆與QR-Code 的功能,這兩項功能也是透過插件來完成,不過,來看看要怎麼時做出這樣的功能。
關於,QRCode 掃描,這個套件 ZXing.Net.Mobile 可以讀取 QRCode 圖片,並且回傳結果到手機中,不過,透過 Visual Studio 2015 專案樣板建立的 PCL 套件,其 PCL 版本使用
Profile111
,然而 ZXing.Net.Mobile 套件使用的 PCL 版本為 Profile78
。因此,當要在各平台的專案中加入這個套件,是沒有問題,不過,當要在 PCL Core 專案中,加入這個套件,卻會產生底下錯誤訊息:錯誤 無法安裝封裝 'ZXing.Net.Mobile 2.0.4.46'。您正嘗試將此封裝安裝到以 '.NETPortable,Version=v4.5,Profile=Profile111' 為目標的專案,但該封裝不包含任何與架構相容的組件參考或內容檔。如需詳細資訊,請連絡封裝作者。 0
所以,需要轉個彎來在 PCL Core 中可以呼叫這個 QRCode 掃描套件,沒錯,那就是要透過
DependencyService
,在下面的說明將會看到這樣的應用。建立標籤式的樣板式頁面方案
- 首先,開啟您的 Visual Studio 2015
- 接著透過 Visual Studio 2015 功能表,選擇這些項目
檔案
>新增
>專案
準備新增一個專案。 - 接著,Visual Studio 2015 會顯示
新增專案
對話窗,請在這個對話窗上,進行選擇Visual C#
>Cross-Platform
>Blank Xaml App (Xamarin.Forms Portable)
- 接著,在最下方的
名稱
文字輸入盒處,輸入XFCALQR
這個名稱,最後使用滑鼠右擊右下方的確定
按鈕。 - 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到
Xamarin Mac Agent Instructions
對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。 - 接著會看到
新的通用Windows專案
對話視窗,此時,您只需要按下確定
按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。 - 最後,整個新的 Xamarin.Forms 專案就建立完成了。
準備安裝套件
請依照底下說明,將這些插件安裝到方案的所有專案中。
行事曆清單來選擇日期
- 滑鼠右擊方案節點
XFCALQR
,接著選擇管理方案的 NuGet 套件
- 在
NuGet - 解決方案
子標籤頁次出現後,點選瀏覽
- 請在搜尋文字輸入盒內,輸入
XamForms.Controls.Calendar
,接著點選Xam.Plugin.Media
項目;在右方點選要安裝到全部的專案內,最後,點選安裝
按鈕
QRCode 掃描
- 滑鼠右擊專案
XFCALQR.Droid
下的參考
節點,滑鼠右擊該節點,接著選擇管理 NuGet 套件
, 在搜尋文字盒內輸入ZXing.Net.Mobile
找到這個套件,點選安裝
按鈕,安裝這個套件。 - 滑鼠右擊專案
XFCALQR.iOS
下的參考
節點,滑鼠右擊該節點,接著選擇管理 NuGet 套件
, 在搜尋文字盒內輸入ZXing.Net.Mobile
找到這個套件,點選安裝
按鈕,安裝這個套件。
QR Code 介面與實作
介面 IQrCodeScanningService
- 對於 QRCode 服務的使用,首先需要定義一個介面,請在核心PCL專案節點上,滑鼠右擊,選擇
加入
>類別
,在加入新項目 - XFCALQR
對話窗下的名稱欄位,輸入IQrCodeScanningService
- 請將底下 C# 程式碼複製到這個檔案內。
ˇ IQrCodeScanningService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XFCALQR
{
public interface IQrCodeScanningService
{
Task<string> ScanAsync();
}
}
Android 實作 QRCodeScannerDroid
- 在 Android 專案下,需要實作 QRCode 服務,請在
XFCALQR.Droid
專案節點上,滑鼠右擊,選擇加入
>類別
,在加入新項目 - XFCALQR.Droid
對話窗下,點選Visual C#
>Class
,最後在下方名稱欄位,輸入QRCodeScannerDroid
- 請將底下 C# 程式碼複製到這個檔案內。
QRCodeScannerDroid.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 XFCALQR.Droid;
using System.Threading.Tasks;
[assembly: Xamarin.Forms.Dependency(typeof(QrCodeScanningService))]
namespace XFCALQR.Droid
{
public class QrCodeScanningService : IQrCodeScanningService
{
public async Task<string> ScanAsync()
{
var options = new ZXing.Mobile.MobileBarcodeScanningOptions();
options.PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE,
};
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var scanResults = await scanner.Scan(options);
if (scanner != null)
{
return scanResults.Text;
}
else
{
return null;
}
}
}
}
iOS 實作 QRCodeScanneriOS
- 在 Android 專案下,需要實作 QRCode 服務,請在
XFCALQR.iOS
專案節點上,滑鼠右擊,選擇加入
>類別
,在加入新項目 - XFCALQR.Droid
對話窗下,點選Apple
>類別
,最後在下方名稱欄位,輸入QRCodeScanneriOS
- 請將底下 C# 程式碼複製到這個檔案內。
QRCodeScanneriOS.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using UIKit;
using XFCALQR.iOS;
[assembly: Xamarin.Forms.Dependency(typeof(QrCodeScanningService))]
namespace XFCALQR.iOS
{
public class QrCodeScanningService : IQrCodeScanningService
{
public async Task<string> ScanAsync()
{
#region 使用 ZXing.Mobile 的 MobileBarcodeScanner
// http://stackoverflow.com/questions/34582728/how-to-find-current-uiviewcontroller-in-xamarin
#region 取得最上層的 UIViewController
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
UIViewController appController = null;
foreach (var foowindow in UIApplication.SharedApplication.Windows)
{
if (foowindow.RootViewController != null)
{
appController = foowindow.RootViewController;
break;
}
}
#endregion
#region QRCode 掃描設定
var options = new ZXing.Mobile.MobileBarcodeScanningOptions();
options.PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE,
};
#endregion
#region 進行 QRCode 掃描
var scanner = new ZXing.Mobile.MobileBarcodeScanner(vc)
{
TopText = "QRCode",
};
try
{
var scanResults = await scanner.Scan(options, true);
if (scanner != null)
{
return scanResults.Text;
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
#endregion
#endregion
}
}
}
MainPage
- 當上述準備工作已經就緒,接下來就可以開始在核心PCL專案內寫相關商業邏輯程式碼了。
- 打開核心PCL 的 MainPage.xaml 檔案,將底下的 XAML 宣告定義複製到這個檔案內。
- 這個頁面宣告內容相當簡單,兩個按鈕與兩個 Label
- 第一個按鈕為啟動 QRCode 掃描的按鈕,當按下這個按鈕,則會出現 QRCode 掃描頁面
- 第二個按鈕為選擇行事曆日期按鈕,當按下這個按鈕,則會出現選擇日期的頁面
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:XFCALQR"
x:Class="XFCALQR.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0, 40, 0, 0" />
</ContentPage.Padding>
<StackLayout
Orientation="Vertical">
<Label x:Name="labelQRCode" LineBreakMode="WordWrap" />
<Button x:Name="buttonScan" Text="掃描QRCode" Clicked="OnbuttonScanClicked" />
<Label x:Name="labelDate" LineBreakMode="WordWrap" />
<Button x:Name="buttonCalendar" Text="選擇日期" Clicked="OnbuttonCalendarClicked" />
</StackLayout>
</ContentPage>
- 請將下列 C# 程式碼複製到 MainPage.xaml.cs內。
- 在建構式內,使用了
MessagingCenter
訂閱了一個訊息事件,也就是當使用者有選擇某個日期之後,其相對應的 callback 就會執行,在這裡,將會取出透過訊息中心所傳遞過來的日期參數,並且將其顯示在指定Label
上。 - 在 掃描QRCode 按鈕事件內, 使用了相依性注入服務
DependencyService
取得當時行動平台實作的 QRCode 掃描物件,並且呼叫ScanAsync
這個方法,取得QRCode掃描結果,並且顯示到指定的Label
。 - 在 選擇日期 按鈕事件內,則是透過
Navigation.PushModalAsync
方法,開啟一個對話窗頁面,該頁面為CalendarPage
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XFCALQR
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<選擇日期訊息, DateTime>(this, "選擇日期", (sender, arg) => {
labelDate.Text = arg.ToString();
});
}
async void OnbuttonScanClicked(object sender, EventArgs e)
{
labelQRCode.Text = "";
var fooQRCode = await DependencyService.Get<IQrCodeScanningService>().ScanAsync();
if (string.IsNullOrEmpty(fooQRCode) == false)
{
labelQRCode.Text = fooQRCode;
}
}
async void OnbuttonCalendarClicked(object sender, EventArgs e)
{
labelDate.Text = "";
var CalendarPage = new CalendarPage();
await Navigation.PushModalAsync(CalendarPage);
}
}
}
行事曆頁面 CalendarPage
- 請在核心PCL節點使用滑鼠右擊該節點,選擇
加入
>新增項目
,當加入新項目 - XFCALQR
對話窗出現後,點選Visual C#
>Cross-Platform
>Forms Xaml Page
,最後在下方名稱欄位的文字輸入盒內,輸入CalendarPage
。 - 請將底下 XAML 宣告定義複製到這個檔案內。
- 在這個行事曆頁面中,新增了一個命名空間 (namespace)
controls
,它的定義為"clr-namespace:XamForms.Controls;assembly=XamForms.Controls.Calendar"
,它的定義是使用分號作為分隔,前半部標示出這個組件的命名空間(在C#內),後半部則是標明這個組件的名稱。日後,當您要在 XAML 內引用其他組件 (Assembly) 內的控制項或者內容,可以可這樣的使用方式。 - 這個頁面使用
StackLayout
版面配置來定位相關控制項要出現的位置,這裡是使用垂直排列的方式。 - 想要顯示行事曆套件的控制項,可以使用這個方式來宣告
<controls:Calendar />
- 最後,宣告兩個按鈕,分別讓使用者確定選取某日期或者取消這次選取動作。
CalendarPage.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:controls="clr-namespace:XamForms.Controls;assembly=XamForms.Controls.Calendar"
x:Class="XFCALQR.CalendarPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" WinPhone="20,20,20,20" />
</ContentPage.Padding>
<Grid>
<StackLayout
Orientation="Vertical"
>
<controls:Calendar
x:Name="cal"
Padding="10,30,10,0"
StartDay="Monday"
SelectedBorderWidth="4"
DisabledBorderColor="Black"
/>
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
>
<Button Text="OK" Clicked="OnOKClicked" />
<Button Clicked="OnCancelClicked" Text="Cancel" />
</StackLayout>
</StackLayout>
</Grid>
</ContentPage>
CalendarPage.cs
- 在 CalendarPage 頁面的 code-behind 程式碼中,分別定義了這兩個按鈕的處理事件。
- 對於 OK 按鈕的處理事件中,先判對使用者是否有點選行事曆上的某個日期,若有,則透過訊息中心(MessagingCenter),將使用者所點選的日期,透過訊息中心傳送出去;當有訂閱該訊息事件的程式碼則會收到該訊息通知,也就會知道使用者選擇了哪個日期。不論選擇日期是否有存在,都會使用
await Navigation.PopModalAsync();
返回到首頁頁面 - 對於 Cancel 按鈕,是很簡單的使用
await Navigation.PopModalAsync();
返回到首頁頁面
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XFCALQR
{
public partial class CalendarPage : ContentPage
{
public DateTime? 選擇日期 { get; set; } = null;
public CalendarPage()
{
InitializeComponent();
}
async void OnOKClicked(object sender, EventArgs e)
{
if (cal.SelectedDate.HasValue == true)
{
選擇日期 = cal.SelectedDate;
MessagingCenter.Send<選擇日期訊息, DateTime>(new 選擇日期訊息(), "選擇日期", 選擇日期.Value);
}
await Navigation.PopModalAsync();
}
async void OnCancelClicked(object sender, EventArgs e)
{
選擇日期 = null;
await Navigation.PopModalAsync();
}
}
}
選擇日期訊息
- 在這裡建立一個空的類別,作為訊息中心的主要通訊類別
- 請在核心PCL專案節點使用滑鼠右擊,選擇
加入
>類別
,接著在名稱欄位旁的文字輸入盒中,填入選擇日期訊息
。最後,請將底下程式碼複製到剛剛產生的檔案內。
選擇日期訊息.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XFCALQR
{
public class 選擇日期訊息
{
}
}
實際執行畫面
Android 執行結果
請在方案總管內,滑鼠右擊
XFCALQR.Droid
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。佈署注意事項
iOS 執行結果
請在方案總管內,滑鼠右擊
XFCALQR.iOS
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。
Hi, Vulcan Lee
回覆刪除我在使用您所提供的QRCode範例碼進行實作時發現,在實體機器上iOS可正確掃描並產生QRCode,可是在Android機器上會閃退。
請問在專案中或實體機器上是否有甚麼權限需要設定呢,謝謝!
Hi Wilson
回覆刪除您可以參考底下官方套件文件,在Android平台下,需要加入適當的使用權限。
https://github.com/Redth/ZXing.Net.Mobile