Xamarin Forms 를 이용한 많은 앱들이 생겨나고 있습니다.

대표 네이버 카페를 가보면

https://play.google.com/store/apps/details?id=kr.njhouse.alltheair

https://play.google.com/store/apps/details?id=com.spoonful_lab.SpoonfulMessenger

등등

위그림에서 보듯이 많은 앱들이 만들어 지고 있습니다.

여기 가입한 분들이 다가 아닐테니.. 더 많을 것입니다.

또한 스타트업 회사들에서도 점점 Xamarin Forms 개발자를 구하는 공고가 조금씩 보이기 시작하고 있습니다.

하지만 아직 표면적으로는 느껴지지는 않는 상황이라는....

그래서 저도 처음 시작할떄 많이 망설이기도 했던게 사실입니다;

어쨌든.... (쓸데없는말이 길었군요)

 

오늘은 Xamarin Forms 으로 계산기를 만들어 보려고 합니다.

대략 순서는 아래와 같습니다.

1. 프로젝트 생성 (cross-flatform)

2. 화면에서 사용될 model 구성

3. 계산기 화면 구성

 

프로젝트를 생성합니다 cross-flatform 을 선택하여 솔루션을 구성합니다.

아래처럼 프로젝트가 생성 됩니다.

전 타이젠도 추가했습니다.

타이젠 추가방법은 이전 포스팅에 있습니다. http://kjcoder.tistory.com/225

 

우선 화면에서 사용될 model 을 생성합니다.

이 model 에 화면에서 처리될(숫자표현, 연산처리등) 내용이 모두 들어가 있습니다.

그 다음 클래스를 추가합니다. StudyViewModel 이라고 명명하겠습니다.

(설명은 코딩내에 다있습니다.)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace XamarinFormsStudy
{
    public class StudyViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// 연산자 입니다.
        /// </summary>
        public string Op { get; set; }
        /// <summary>
        /// 계산할 데이터 입니다. 이전입력값
        /// </summary>
        public double Op1 { get; set; }
        /// <summary>
        /// 계산할 데이터 입니다. 현재입력값
        /// </summary>
        public double Op2 { get; set; }
        /// <summary>
        /// 출력창에 입력문자를 보여주도록하는 명령입니다.
        /// </summary>
        public ICommand AddCharCommand { protected set; get; }
        /// <summary>
        /// 출력창의 문자를 하나씩 삭제하는 명령입니다.
        /// </summary>
        public ICommand DeleteCharCommand { protected set; get; }
        /// <summary>
        /// 출력창의 모든 문자를 삭제하는 명령입니다.
        /// </summary>
        public ICommand ClearCommand { protected set; get; }
        /// <summary>
        /// 연산자 입력시 처리하는 명령입니다.
        /// </summary>
        public ICommand OperationCommand { protected set; get; }
        /// <summary>
        /// 연산결과를 도출하는 명령입니다.
        /// </summary>
        public ICommand CalcCommand { protected set; get; }

        // 출력될 문자들 담아둘 변수
        string inputString = "";
        public string InputString
        {
            protected set
            {
                if (this.inputString != value)
                {
                    this.inputString = value;
                    OnPropertyChanged("InputString");
                    this.DisplayText = this.inputString;

                    //삭제 버튼을 활성화/비활성화 합니다.
                    ((Command)this.DeleteCharCommand).ChangeCanExecute();
                }
            }
            get { return this.inputString; }
        }
          
        // 출력 텍스트 박스에 대응되는 필드
        string displayText = "";
        public string DisplayText
        {
            protected set
            {
                if (this.displayText != value)
                {
                    this.displayText = value;
                    OnPropertyChanged("DisplayText");
                }
            }

            get { return this.displayText; }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public StudyViewModel()
        {
            // 출력창에 입력 문자를 출력합니다.
            this.AddCharCommand = new Command<string>((Key) => { this.InputString += Key; });
            // 입력문자열이 0보다 큰 경우 마지막에서 하나씩 삭제합니다.
            this.DeleteCharCommand = new Command(
            (nothing) =>
            {
                this.InputString = this.InputString.Substring(0, this.InputString.Length - 1);
            },
            (nothing) =>
            {
                return this.InputString.Length > 0;
            }
            );

            // 초기화
            this.ClearCommand = new Command((nothing) =>
            {
                this.InputString = "";
            });

            // 연산자가 들어오면 연산자와 입력문자를 전역에 담습니다.
            this.OperationCommand = new Command<string>((key) =>
            {
                this.Op = key;
                this.Op1 = Convert.ToDouble(this.InputString);
                this.InputString = "";
            });

            // 전역에 담겨진 연산자와 입력문자열 기준으로 계산하여 출력창에 나타냅니다.
            this.CalcCommand = new Command<string>((nothing) =>
            {
                this.Op2 = Convert.ToDouble(this.InputString);

                switch (this.Op)
                {
                    case "+":  this.InputString = (this.Op1 + this.Op2).ToString(); break;
                    case "-": this.InputString = (this.Op1 - this.Op2).ToString(); break;
                    case "*": this.InputString = (this.Op1 * this.Op2).ToString(); break;
                    case "/": this.InputString = (this.Op1 / this.Op2).ToString(); break;

                }
           
            });
        }

        /// <summary>
        /// 항목변경에 따른 이벤트입니다.
        /// </summary>
        /// <param name="propertyName"></param>
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

 

ContentPage 를 추가합니다.

아래 처럼 코딩합니다. (설명은 코딩내에 다있습니다.)

<?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:XamarinFormsStudy;assembly=XamarinFormsStudy"
             x:Class="XamarinFormsStudy.CalcPage">

    <Grid HorizontalOptions="Center" VerticalOptions="Center">
        <!--그리드에 바인딩될 모델을 설정합니다.-->
        <Grid.BindingContext>
            <local:StudyViewModel/>
        </Grid.BindingContext>
        <!--계산기의 기본 레이아웃을 잡습니다. row 6, col 4-->
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
       
        <!--상단에 계산기 인걸 표시해줍니다. "Calc"-->
         <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Frame Grid.Column="0">
                <Label Text="Calc"
                       HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
                       IsVisible="True" FontAttributes="Bold" TextColor="Black"/>
            </Frame>
        </Grid>

        <!--가장 윗줄인 숫자가 보여질 영역과 삭제, 초기화 버튼을 위치시킵니다.-->
        <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Frame Grid.Column="0" OutlineColor="Accent">
                <Label Text="{Binding DisplayText}"/>
            </Frame>
           
            <!--여기서 각버튼마다 model 에 정의된 명령을 연결시켜주었습니다.-->
            <Button Text="<"   Command="{Binding DeleteCharCommand}"   Grid.Column="1" BorderWidth="0"/>
            <Button Text="C"    Command="{Binding ClearCommand}"        Grid.Column="2" BorderWidth="0"/>
        </Grid>
        <!--
        숫자와 연산기호를 정의합니다.
        숫자와 연산기호 또한 model 에 정의된 명령을 연결시켜줍니다.
        -->
        <Button Text="1" Command="{Binding AddCharCommand}" CommandParameter="1" Grid.Row="2" Grid.Column="0"/>
        <Button Text="2" Command="{Binding AddCharCommand}" CommandParameter="2" Grid.Row="2" Grid.Column="1"/>
        <Button Text="3" Command="{Binding AddCharCommand}" CommandParameter="3" Grid.Row="2" Grid.Column="2"/>
        <Button Text="+" Command="{Binding OperationCommand}" CommandParameter="+" Grid.Row="2" Grid.Column="3"/>
       
        <Button Text="4" Command="{Binding AddCharCommand}" CommandParameter="4" Grid.Row="3" Grid.Column="0"/>
        <Button Text="5" Command="{Binding AddCharCommand}" CommandParameter="5" Grid.Row="3" Grid.Column="1"/>
        <Button Text="6" Command="{Binding AddCharCommand}" CommandParameter="6" Grid.Row="3" Grid.Column="2"/>
        <Button Text="-" Command="{Binding OperationCommand}" CommandParameter="-" Grid.Row="3" Grid.Column="3"/>
       
        <Button Text="7" Command="{Binding AddCharCommand}" CommandParameter="7" Grid.Row="4" Grid.Column="0"/>
        <Button Text="8" Command="{Binding AddCharCommand}" CommandParameter="8" Grid.Row="4" Grid.Column="1"/>
        <Button Text="9" Command="{Binding AddCharCommand}" CommandParameter="9" Grid.Row="4" Grid.Column="2"/>
        <Button Text="*" Command="{Binding OperationCommand}" CommandParameter="*" Grid.Row="4" Grid.Column="3"/>
       
        <Button Text="0" Command="{Binding AddCharCommand}" CommandParameter="0" Grid.Row="5" Grid.Column="0"/>
        <Button Text="." Command="{Binding AddCharCommand}" CommandParameter="." Grid.Row="5" Grid.Column="1"/>
        <Button Text="=" Command="{Binding CalcCommand}" CommandParameter="=" Grid.Row="5" Grid.Column="2"/>
        <Button Text="/" Command="{Binding OperationCommand}" CommandParameter="/" Grid.Row="5" Grid.Column="3"/>

    </Grid>
</ContentPage>

계산기가 만들어졌습니다.

이제 결과를 확인해 볼까요...

각 장치마다 UI 가 조금씩 다릅니다.

그럼 각 장치에 맞는 추가 코딩을 넣어주어야합니다.

이런게 Xamarin Forms 의 한계점이라고 볼수 있습니다;;;

 

Tzien

 

 

Android

 

iOS

 

Universal

 

소스를 첨부하고 싶지만 너무 용량이 커서 Git 주소로 대채합니다.

https://github.com/knagjun/XamarinFormsStudy

+ Recent posts