練習 - 建立電話號碼轉譯器應用程式
現在該是進行我們概念證明的時候了。 我們將建置一個 UI,此 UI 不僅會利用 Xamarin.Forms,也會利用將撥打電話的 Xamarin.Essentials NuGet 套件。
此應用程式會讓使用者在輸入欄位中輸入文字,並會將該文字轉譯成數字。 它會使用電話鍵台上顯示的字母作為轉譯基礎。 例如,因為數字 "2" 代表 "abc" 這三個字母,所以字母 "cab" 會轉譯成 "222"。
開啟 Phoneword 解決方案
您將使用在前一個練習中建立的 Phoneword 解決方案來繼續進行操作。 如果您尚未在 Visual Studio 中開啟該解決方案,請開啟它。
新增新的 C# 原始程式檔
- 在名為 Phoneword 的共用專案上按一下滑鼠右鍵,然後選取 [新增]>[類別…]。
- 將檔案命名為 PhonewordTranslator.cs。
新增轉譯邏輯
將下列靜態類別程式碼放到新的 PhonewordTranslator.cs 原始程式檔中。 此程式碼是單一 public static
方法,會將號碼從英數字元文字轉譯成一般數字電話號碼。
using System.Text;
namespace Core
{
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return null;
raw = raw.ToUpperInvariant();
var newNumber = new StringBuilder();
foreach (var c in raw)
{
if (" -0123456789".Contains(c))
newNumber.Append(c);
else
{
var result = TranslateToNumber(c);
if (result != null)
newNumber.Append(result);
// Bad character?
else
return null;
}
}
return newNumber.ToString();
}
static bool Contains(this string keyString, char c)
{
return keyString.IndexOf(c) >= 0;
}
static readonly string[] digits = {
"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
};
static int? TranslateToNumber(char c)
{
for (int i = 0; i < digits.Length; i++)
{
if (digits[i].Contains(c))
return 2 + i;
}
return null;
}
}
}
重組未定案程式碼的結構
接著,讓我們稍微重組程式碼的結構。 我們將建立自己的以程式碼為基礎的 UI,因此我們將從專案範本中刪除已產生的 XAML UI。
在 [方案總管] 中現有的 MainPage.xaml 檔案上按一下滑鼠右鍵,然後選擇 [刪除]。 此動作會一併刪除程式碼後置 MainPage.xaml.cs 檔案。
在名為
MainPage
的新檔案中建立新類別。 您可以使用與上面相同的程序來建立新類別檔案。讓類別衍生自
ContentPage
。 新增using Xamarin.Forms
陳述式,因為ContentPage
位於Xamarin.Forms
命名空間中。using Xamarin.Forms; ... public class MainPage : ContentPage { public MainPage() { } }
建立 Phoneword 的 UI
接著,我們需要描述 Phoneword 的使用者介面。 我們使用的是 Xamarin.Forms 中定義的控制項,其會在每個專案中使用原生實作來加以轉譯。
- 在於 MainPage.xaml.cs 中工作的情況下,在
MainPage
建構函式執行下列操作。 - 將頁面的
Padding
全部設定為 "20"。 設定邊界可確保控制項不會抵到螢幕邊緣。 - 建立
Spacing = 15
的StackLayout
。 - 為 Phoneword UI 建立必要的控制項:
- 將控制項新增至
StackLayout
。 - 將
StackLayout
指派給MainPage
的Content
屬性。
public class MainPage : ContentPage
{
Entry phoneNumberText;
Button translateButton;
Button callButton;
public MainPage()
{
this.Padding = new Thickness(20, 20, 20, 20);
StackLayout panel = new StackLayout
{
Spacing = 15
};
panel.Children.Add(new Label {
Text = "Enter a Phoneword:",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
});
panel.Children.Add(phoneNumberText = new Entry {
Text = "1-855-XAMARIN",
});
panel.Children.Add(translateButton = new Button {
Text = "Translate"
});
panel.Children.Add(callButton = new Button {
Text = "Call",
IsEnabled = false,
});
this.Content = panel;
}
}
回應按鈕點選
讓處理常式訂閱 [轉譯] 按鈕的 Clicked
事件。 使用名為 OnTranslate
的方法。 此方法會採用 object
和 EventArgs
作為參數。
處理常式應該使用 PhonewordTranslator.ToNumber
方法來轉譯輸入的值。 處理常式應該將結果儲存在名為 translatedNumber
的欄位中。
以下是程式碼的一些其他提示:
- 從
Entry
控制項的Text
屬性擷取電話號碼。 PhonewordTranslator
類別位於Core
命名空間中。- 如果號碼無法轉譯,
PhonewordTranslator.ToNumber
方法就會傳回null
。
當您完成時,您的程式碼應該與下列類似:
public class MainPage : ContentPage
{
...
string translatedNumber;
public MainPage()
{
...
translateButton.Clicked += OnTranslate;
this.Content = panel;
}
private void OnTranslate(object sender, EventArgs e)
{
string enteredNumber = phoneNumberText.Text;
translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber);
if (!string.IsNullOrEmpty(translatedNumber))
{
// TODO:
}
else
{
// TODO:
}
}
}
更新 UI
接著,讓我們新增一些邏輯來變更 [撥號] 按鈕的 Text
,以在成功轉譯電話號碼時包含該電話號碼。 您可以使用儲存在 translatedNumber
欄位中的值。 此外,請根據成功的轉譯,啟用和停用按鈕。 例如,如果 TranslateNumber
傳回 null
,請停用按鈕,但如果成功,則啟用按鈕。
- 使用
IsEnabled
屬性來啟用和停用按鈕。 - 如果號碼轉譯失敗,請務必重設 [撥號] 按鈕的
Title
(也就是移除電話號碼)。
private void OnTranslate(object sender, EventArgs e)
{
string enteredNumber = phoneNumberText.Text;
translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber);
if (!string.IsNullOrEmpty(translatedNumber))
{
callButton.IsEnabled = true;
callButton.Text = "Call " + translatedNumber;
}
else
{
callButton.IsEnabled = false;
callButton.Text = "Call";
}
}
將事件處理常式新增至撥號按鈕
讓處理常式訂閱 [撥號]Button
的 Clicked
事件。 在目前的 translateButton.Clicked
處理常式之後新增處理常式。
public MainPage()
{
...
translateButton.Clicked += OnTranslate;
callButton.Clicked += OnCall;
this.Content = panel;
}
...
void OnCall(object sender, System.EventArgs e)
{
}
顯示警示
下列步驟會將邏輯新增至 OnCall
方法。
使用
Page.DisplayAlert
來提示使用者,以詢問使用者是否要撥打號碼。DisplayAlert
方法會傳回Task
。 將async
關鍵字新增至 OnCall,然後等候 (await
) 該呼叫顯示警示 (DisplayAlert
)。DisplayAlert
會採用標題、訊息及用於「接受」和「取消」按鈕文字的兩個字串。 它會傳回一個布林值,指出是否已按下 [接受] 按鈕來關閉對話方塊。
使用下列參數:
屬性 | 值 |
---|---|
標題 | 「撥打號碼」 |
訊息 | 「是否要撥打 xxxx」(使用轉譯的號碼)。 |
「是」和「否」 | 適用於 [接受] 和 [取消] 按鈕。 |
async void OnCall(object sender, System.EventArgs e)
{
if (await this.DisplayAlert(
"Dial a Number",
"Would you like to call " + translatedNumber + "?",
"Yes",
"No"))
{
// TODO: dial the phone
}
}
執行應用程式
在任何平台上建置並執行。 其應該顯示警示,並讓您透過「是」或「否」回應來關閉警示。
使用 Xamarin.Essentials 程式庫來撥打電話
接著,我們將使用稱為 Xamarin.Essentials 的跨平台程式庫,此程式庫會透過單一 API 提取數個平台專用函式。 Xamarin.Essentials 提供一個電話撥號 API,可在 iOS 和 Android 平台上撥打電話。 此程式庫會以我們新增至每個專案的 NuGet 套件形式提供。 因為其可為我們的平台及共用抽象概念提供實作,所以我們會將其新增至所有專案。
注意
如果您的專案目標 Android 版本設定為 Android 11 (R API 30),則必須更新 Android 資訊清單。 深入了解如何使用與新套件可見度需求搭配使用的查詢進行更新。
為 Android 專案新增權限
若要在 Android 上撥打電話,需要執行其他步驟。 我們必須明確地宣告撥號權限。
開啟 Android 專案的 [屬性]。 (在 [方案總管] 中的專案名稱上按一下滑鼠右鍵,然後選取 [屬性])
選取 [Android 資訊清單]。
在 [必要權限] 區段中,選取
CALL_PHONE
權限旁邊的方塊 (請參閱下方)。
呼叫 Xamarin.Essentials 撥號程式抽象概念
我們現在可以在共用程式碼中呼叫 Xamarin.Essentials 中的撥號程式系統。
開啟 MainPage.xaml.cs,然後以下列程式碼取代 OnCall
方法中的 TODO
行。 新增 using Xamarin.Essentials
陳述式以讓 PhoneDialer
變成可用類別。
using Xamarin.Essentials;
...
async void OnCall(object sender, System.EventArgs e)
{
if (await this.DisplayAlert(
"Dial a Number",
"Would you like to call " + translatedNumber + "?",
"Yes",
"No"))
{
try
{
PhoneDialer.Open(translatedNumber);
}
catch (ArgumentNullException)
{
await DisplayAlert("Unable to dial", "Phone number was not valid.", "OK");
}
catch (FeatureNotSupportedException)
{
await DisplayAlert("Unable to dial", "Phone dialing not supported.", "OK");
}
catch (Exception)
{
// Other error has occurred.
await DisplayAlert("Unable to dial", "Phone dialing failed.", "OK");
}
}
}
執行應用程式
- 使用您選擇的平台來執行應用程式。 請務必對轉譯和撥號按鈕都進行嘗試。
- 如果您有時間,請在每個支援的平台上都執行此應用程式,然後嘗試逐步執行程式來查看它跳到平台專用程式碼。 若要更有趣一些,請嘗試在真實的裝置上執行!
許多模擬器都無法正確地模擬撥打電話的情況。 不過,Android SDK 虛擬裝置除外。 在其他模擬平台上,您的程式碼可能會在嘗試撥打電話時擲回例外狀況。 若發生例外狀況,您可以將撥打電話的程式碼標記為註解,或將其包裝在 try
/ catch
陳述式中。
總結
在本練習中,您已使用頁面和檢視將自訂 UI 新增至應用程式。 您也使用 iOS 和 Android 中可用的平台專用 API 來新增撥打電話的支援。
您可以在所複製或下載練習存放庫複本內的 [src]>[exercise1]>[final] 資料夾中,檢視已完成的解決方案。