Xamarin.Forms는 화면상의 컨텐츠 위치를 결정하는 몇가지 레이아웃 및 기능들을 제공하고 있습니다.

각 레이아웃 컨트롤은 다음과 같습니다.

StackLayout 
: 수평이나 수직 방향으로 순차적으로 정렬을 원할때 사용합니다.
  StackLayout에서 뷰들은 중앙, 왼쪽, 오른쪽으로 정렬될 수 있습니다.

<StackLayout Orientation="Horizontal">
  <Label HorizontalOptions="StartAndExpand" Text="Label" />
  <Button HorizontalOptions="End" Text="Button" />
</StackLayout>

AbsoluteLayout 
: 절대 값이나 절대 비율을 기준으로 좌표 및 크기를 설정하여 뷰들을 정렬할때 사용됩니다. 
  AbsoluteLayout은 레이어 뷰들을 왼쪽, 오른쪽, 중앙으로 고정시킬 때 사용이 가능합니다.

아래 예제를 실행하기 위해선 이미지를 가져와야합니다.
Image 포스팅 참고해주세요 => http://kjcoder.tistory.com/325

위 작업이 마무리 되면 아래처럼 xaml 을 작성합니다.

<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.AbsoluteLayoutPage">
    <ContentPage.Content>
        <AbsoluteLayout Padding="15">
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Rotation="30" Source="{local:ImageResource XamarinFormsStudy.bottom.png}" />
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Rotation="60" Source="{local:ImageResource XamarinFormsStudy.middle.png}" />
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Source="{local:ImageResource XamarinFormsStudy.cover.png}" />
        </AbsoluteLayout>
    </ContentPage.Content>
</ContentPage>

 

 RelativeLayout
: 뷰들의 부모의 차원 및 위치에 대한 상대적인 제약을 설정하여 정렬할 때 사용됩니다.

<RelativeLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
  <BoxView Color="Blue" HeightRequest="50" WidthRequest="50"
    RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = 0}"
    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = 0}" />
  <BoxView Color="Red" HeightRequest="50" WidthRequest="50"
    RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = .9}"
    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = 0}" />
  <BoxView Color="Gray" WidthRequest="15" x:Name="pole"
    RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.75}"
    RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = .45}"
    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = .25}" />
  <BoxView Color="Green"
    RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.10, Constant=10}"
    RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width, Factor=.2, Constant=20}"
    RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=X, Constant=15}"
    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=Y, Constant=0}" />
</RelativeLayout>

Grid
: 그리드 형태로 뷰들을 정렬할 때 사용됩니다.
  Row와 Column은 절대 값이나 비율을 기준으로 정해질 수 있습니다.

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Button Text="1" Grid.Row="0" Grid.Column="0" />
  <Button Text="2" Grid.Row="0" Grid.Column="1" />
  <Button Text="3" Grid.Row="0" Grid.Column="2" />
  <Button Text="4" Grid.Row="1" Grid.Column="0" />
  <Button Text="5" Grid.Row="1" Grid.Column="1" />
  <Button Text="6" Grid.Row="1" Grid.Column="2" />
  <Button Text="7" Grid.Row="2" Grid.Column="0" />
  <Button Text="8" Grid.Row="2" Grid.Column="1" />
  <Button Text="9" Grid.Row="2" Grid.Column="2" />
  <Button Text="0" Grid.Row="3" Grid.Column="1" />
  <Button Text="*" Grid.Row="3" Grid.Column="2" />
</Grid>

 

ScrollView 
: 뷰들이 화면의 영역내에 전체가 표시될 수 없을 때 스크롤을 제공하기 위해 사용됩니다.

 

참고

https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/

https://developer.xamarin.com/api/type/Xamarin.Forms.AbsoluteLayout/

GitHub > https://github.com/knagjun/XamarinForms

'Xamarin' 카테고리의 다른 글

(Xamarin Forms) Error - ResolveLibraryProjectImports  (0) 2017.07.05
(Xamarin Forms) Error - XamlCTask  (0) 2017.07.05
(Xamarin Forms) 3.Layout  (0) 2017.07.05
(Xamarin Forms) 2.MasterDetailPage  (0) 2017.06.30
(Xamarin Forms) 1.ContentPage  (0) 2017.06.29
(Xamarin Forms) StartTimer  (0) 2017.06.22

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