코젤브

실습: 전화 번호 변환기 앱 만들기 본문

컴공의 일상/.NET MAUI

실습: 전화 번호 변환기 앱 만들기

코딩하는 젤리 2024. 7. 9. 12:49

이제 실습을 통해 배운 개념을 적용해보자!

전화 걸기 앱에 대한 UI를 생성하고 이 UI 뒤에 있는 논리를 구현

.NET MAUI 및 .NET MAUI Essentials 패키지의 UI 기능을 활용하여 전화를 거는 UI를 빌드합니다.

  • 앱을 사용하면 사용자가 텍스트를 입력 필드에 입력하고 해당 텍스트를 숫자로 변환시킬 수 있습니다.
  • 전화 키패드에 표시되는 문자를 변환 기준으로 사용합니다.
    • 예를 들어 
      • cab는 222로 변환 (숫자 2에는 a, b, c라는 세 개의 문자가 모두 있으므로)

 

무슨 의미인지 헷갈렸는데 아래 키패드를 말하는 것 같습니다. 아래 그림을 참고하시면 이해가 쉽습니다!

영어 입력 시 그에 맞는 번호가 출력! (출처: https://cong4u.tistory.com/404)

 

 

변환 논리 추가

클래스 파일의 콘텐츠를 다음 코드로 바꾸고 파일을 저장합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyMauiApp
{
    internal static class PhonewordTranslator
    {
        // [문자열을 입력받아 변환된 숫자 문자열을 반환하는 메서드]
        public static string ToNumber(string raw)
        {
            if (string.IsNullOrWhiteSpace(raw)) // 입력 문자열이 비어 있거나 공백만 있는 경우, null을 반환
                return null;

            raw = raw.ToUpperInvariant(); // 입력 문자열을 대문자로 변환하여 일관된 처리를 보장

            var newNumber = new StringBuilder(); // 변환된 숫자를 저장할 StringBuilder 객체를 초기화
            foreach (var c in raw) // 입력 문자열의 각 문자를 순회
            {
                if (" -0123456789".Contains(c)) // 문자 c가 공백, 하이픈 또는 숫자인 경우, 그대로 추가
                    newNumber.Append(c);
                else
                {
                    var result = TranslateToNumber(c); // 문자를 숫자로 변환
                    if (result != null)
                        newNumber.Append(result);
                    // Bad character?
                    else // 변환할 수 없는 문자가 포함된 경우, null을 반환
                        return null;
                }
            }
            return newNumber.ToString(); // 변환된 숫자 문자열을 반환
        }

        // [문자열에서 특정 문자의 존재 여부를 확인하는 확장 메서드]
        static bool Contains(this string keyString, char c)
        {
            return keyString.IndexOf(c) >= 0; // IndexOf를 사용하여 문자가 문자열에 포함되어 있는지 확인
        }

        // [키패드의 알파벳 그룹을 나타내는 digits 배열]
        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; // 어떤 알파벳 그룹에도 포함되지 않는 경우 null을 반환
        }
    }
}

PhonewordTranslator 클래스의 정적 메서드 ToNumber는 영숫자 텍스트의 숫자를 일반 숫자 전화 번호로 변환합니다.

[ToNumber 메서드]

 

  • 문자열을 입력받아 변환된 숫자 문자열을 반환하는 메서드
  • 입력 문자열이 비어 있거나 공백만 있는 경우 null을 반환합니다.
  • 입력 문자열을 대문자로 변환하여 일관된 처리를 보장합니다.
  • 변환된 숫자를 저장할 StringBuilder 객체를 초기화합니다.
  • 입력 문자열의 각 문자를 순회합니다.
  • 문자 c가 공백, 하이픈 또는 숫자인 경우 그대로 추가합니다.
  • 문자를 숫자로 변환합니다. 변환할 수 없는 문자가 포함된 경우 null을 반환합니다.
  • 변환된 숫자 문자열을 반환합니다.

 

 

[Contains 확장 메서드]

  • 문자열에서 특정 문자의 존재 여부를 확인하는 확장 메서드
  • IndexOf를 사용하여 문자가 문자열에 포함되어 있는지 확인합니다.

 

[digits 배열]

  • 전화기 키패드의 알파벳 그룹을 나타내는 배열입니다. 예를 들어, 'ABC'는 숫자 2에 대응

 

[TranslateToNumber 메서드]

  • 문자를 숫자로 변환하는 메서드
    • for (int i = 0; i < digits.Length; i++)는 각 알파벳 그룹을 순회합니다.
    • if (digits[i].Contains(c)) return 2 + i;는 문자가 해당 알파벳 그룹에 포함되면 대응하는 숫자를 반환합니다.
    • return null;은 문자가 어떤 알파벳 그룹에도 포함되지 않는 경우 null을 반환합니다.

 

새로운 Page 만들기

기존 MainPage를 유지하고 싶었기 때문에 버튼을 누르면 DigitsPage로 넘어가도록 코드를 수정해보자

1. DigitsPage 클래스 추가 ( DigitsPage.xaml & DigitsPage.xaml.cs)

2. MainPage에 버튼 추가 및 네비게이션 구현 ( MainPage.xaml & MainPage.xaml.cs 수정)

  • MainPage.xaml에 Button 추가 
<Button Text="Go to Digits Page"
                Clicked="OnNavigateToDigitsPage"/>
  • MainPage.xaml.cs에 OnNavigateToDigitsPage 함수 추가
private async void OnNavigateToDigitsPage(object sender, EventArgs e)
        {
            await Shell.Current.GoToAsync(nameof(DigitsPage));
        }

3. AppShell에 라우트 등록 ( AppShell.xaml.cs & AppShell.xaml)

  • AppShell.xaml.cs 라우트 등록
// AppShell.xaml.cs
namespace MyMauiApp
{
    public partial class AppShell : Shell
    {
        public AppShell()
        {
            InitializeComponent();
            Routing.RegisterRoute(nameof(DigitsPage), typeof(DigitsPage)); // 새로운 페이지 라우팅 추가
        }
    }
}

 

UI 만들기

DigitsPage.xaml 과 DigitsPage.xaml.cs 파일에 수정

DigitsPage.xaml에서 페이지 레이아웃을 정의하고 있다.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyMauiApp.DigitsPage"
             Title="DigitsPage">
    <!-- VerticalStackLayout : 자식 요소를 수직으로 나타내고 있음 -->
    <VerticalStackLayout Spacing="15" Padding="20">
        <!-- Label: 텍스트 표시 -->
        <Label Text = "Enter a Phoneword" 
               FontSize ="20"/>
        <!-- Entry: 텍스트 입력 필드 -->
        <Entry x:Name = "PhoneNumberText" 
               Text = "1-555-NETMAUI" />
        <!-- Button -->
        <Button x:Name = "TranslateButton"
                Text = "Translate"
                Clicked = "OnTranslate"/>
        <Button x:Name = "CallButton"
                Text = "Call"
                IsEnabled = "False"
                Clicked = "OnCall"/>
    </VerticalStackLayout>
</ContentPage>
  • VerticalStackLayout: 자식 요소를 수직으로 나열
  • Label: "Enter a Phoneword"라는 텍스트를 표시
  • Entry: 사용자가 전화 단어를 입력할 수 있는 텍스트 입력 필드
    • x:Name 속성으로 컨트롤에 이름을 지정
  • Button (TranslateButton): 클릭 시 전화 단어를 숫자로 번역하는 버튼
  • Button (CallButton): 클릭 시 전화 걸기를 시도하는 버튼 (처음에는 비활성화)

 

TranslateButton & CallButton 관련 Clicked 이벤트 메서드

namespace MyMauiApp;

public partial class DigitsPage : ContentPage // 기본 페이지 유형인 ContentPage 상속
{
	public DigitsPage() // 생성자 : 컴포넌트 초기화
	{
		InitializeComponent(); // XAML 파일의 구성요소 초기화
	}

    string translatedNumber; // 번역된 번호 저장 필드

    // TranslateButton 클릭 이벤트 핸들러
    private void OnTranslate(object sender, EventArgs e)
    {
        string enteredNumber = PhoneNumberText.Text; // 입력된 전화 단어 가져오기
        translatedNumber = MyMauiApp.PhonewordTranslator.ToNumber(enteredNumber); // 숫자로 변환

        if (!string.IsNullOrEmpty(translatedNumber)) // 변역된 번호가 비어있지 않다면
        {
            CallButton.IsEnabled = true; // 버튼 활성화
            CallButton.Text = "Call " + translatedNumber; // 텍스트 업데이트
        }
        else // 변환된 번호가 비어있다면
        {
            CallButton.IsEnabled = false; // 버튼 비활성화
            CallButton.Text = "Call"; 
        }
    }
    
    // CallButton 클릭 이벤트 핸들러
    async void OnCall(object sender, System.EventArgs e)
    {
        if (await this.DisplayAlert( // DisplayAlert : 알림 대화 상자 표시
        "Dial a Number",
        "Would you like to call " + translatedNumber + "?",
        "Yes",
        "No"))
        {
            // TODO: dial the phone
        }
    }
}

 

  • DigitsPage 클래스는 ContentPage(기본 페이지 유형) 상속받음
  • DigitsPage 생성자에서 InitializeComponent()를 호출하여 XAML 파일의 구성 요소를 초기화
  • translatedNumber는 번역된 전화 번호를 저장하는 필드
  • OnTranslate 메서드는 TranslateButton 클릭 이벤트 핸들러
    • PhoneNumberText.Text에서 입력된 전화 단어를 가져옴
    • PhonewordTranslator.ToNumber(enteredNumber)를 호출하여 전화 단어를 숫자로 변환
    • 변환된 번호가 유효한 경우 CallButton을 활성화하고 텍스트를 업데이트
    • 변환된 번호가 유효하지 않은 경우 CallButton을 비활성화하고 기본 텍스트로 설정
  • OnCall 메서드는 CallButton 클릭 이벤트 핸들러
    • DisplayAlert를 호출하여 사용자에게 전화를 걸지 여부를 물음
      • public Task<bool> DisplayAlert(string title, string message, string accept, string cancel);
    • 사용자가 "Yes"를 선택한 경우, 실제 전화 걸기 기능을 구현 가능 (아직 미완성 // TODO로 주석 처리)

 

 

OnCall 메서드 업데이트 (전화 걸기 기능 구현)

// CallButton 클릭 이벤트 핸들러
async void OnCall(object sender, System.EventArgs e)
{
    if (await this.DisplayAlert( // DisplayAlert : 알림 대화 상자 표시
    "Dial a Number",
    "Would you like to call " + translatedNumber + "?",
    "Yes",
    "No"))
    {
        // 전화 번호로 전화 걸기
        try
        {
            if (PhoneDialer.Default.IsSupported) 
                // PhoneDialer 클래스 : 전화 걸기 기능(및 기타)의 추상화를 제공
                PhoneDialer.Default.Open(translatedNumber); // Open() : 제공된 번호를 호출하려고 시도
        }
        catch (ArgumentNullException)
        {
            await DisplayAlert("Unable to dial", "Phone number was not valid.", "OK");
        }
        catch (Exception)
        {
            // Other error has occurred.
            await DisplayAlert("Unable to dial", "Phone dialing failed.", "OK");
        }
    }
}

 

최종 화면

 

실습후기

winForm 대비 빌드가 엄청 오래걸리네요.. 

 


참고 문헌

 

연습: 전화 번호 변환기 앱 만들기 - Training

전화 번호 변환기 앱에 대한 UI를 만들고 논리를 작성합니다.

learn.microsoft.com