자알못 자마린 – Xamarin.Forms 입력양식 및 설정페이지 만들기 기초

Table of Content

스위치(Switch)

Switch는 활성화/비활성화 여부를 시각적으로 보여주는 아이콘이다.

주요 속성

  • isToggled: 처음 실행되었을 때 Switch의 활성화 여부 설정

주요 이벤트

  • Toggled: Switch의 상태가 변했을 때 발생

 

Switch 제어: x:Name 속성 사용

아래 예제는 Switch 활성화 여부에 따라 Label을 보여주거나 가려주는 예제.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <Switch IsToggled="true" Toggled="Handle_Toggled"></Switch>
        <Label Text="내용" x:Name="label"></Label>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
        {
            label.IsVisible = e.Value;
        }
    }
}

실행화면

 

Switch 제어: 데이터 바인딩(Data Binding) 사용

데이터 바인딩(Data Binding)을 사용하면 C# 코드로 이벤트 처리기를 구현하지 않아도 된다. 데이터 바인딩에 관한 설명은 ‘자알못 자마린: Xamarin.Forms XAML 기초’ 글을 참고.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <Switch IsToggled="true" x:Name="switch"></Switch>
        <Label Text="내용" IsVisible="{Binding Source={x:Reference switch}, Path=IsToggled}"></Label>
    </StackLayout>
</ContentPage>

실행결과

생략… 바로 위의 예제 결과와 똑같음.

 

슬라이더(Slider)

Slider는 좌우로 슬라이드하여 값을 설정할 수 있는 양식이다. 기본적으로 0과 1사이의 double형로 지정된다.

주요 속성

  • Maximum: 최대값 (Minimum보다 먼저 설정해주어야 충돌 방지)
  • Minimum: 최소값
  • Value: 처음 실행되었을 때의 값

주요 이벤트

  • ValueChanged: Slider의 값이 바뀔 때 발생
    • e.OldValue: 값이 바뀌기 전의 값(double형)
    • e.NewValue: 값이 바뀐 후의 값(double형)

아래 예제는 슬라이더의 값을 표시하는 Label을 XAML 데이터 바인딩으로 구현한 예제.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <!-- Slider의 최대/최소값 설정 시 Maximum 속성을 먼저 설정해야 충돌이 나지 않음 -->
        <Slider x:Name="slider" Maximum="255" Minimum="10" ValueChanged="Handle_ValueChanged"></Slider>
        <Label Text="{Binding Source={x:Reference slider}, Path=Value, StringFormat='{0:N0}'}"></Label>
    </StackLayout>
</ContentPage>

실행화면

 

스테퍼(Stepper)

Stepper는 값을 올리거나 낮출 수 있는 버튼이다.

주요 속성

  • Minimum: 최소값
  • Maximum: 최대값
  • Increment: 증분값

주요 이벤트

  • ValueChanged: Stepper의 값이 바뀔 때 발생

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <Stepper x:Name="stepper" Minimum="0" Maximum="100" Increment="5"></Stepper>
        <Label Text="{Binding Source={x:Reference stepper}, Path=Value}"></Label>
    </StackLayout>
</ContentPage>

실행화면

 

엔트리(Entry)

Entry는 값을 입력받을 수 있는 글상자다. 문자열을 입력받을 수 있을뿐만 아니라 숫자, 이메일, 비밀번호를 입력받을 수 있도록 유형을 지정할 수 있다.

주요 속성

  • Text: 텍스트 값
  • Keyboard: 입력유형(Default, Email, Numeric, Telephone, Text, Url)
  • Placeholder: 아무것도 입력되지 않았을 때 표시할 텍스트
  • IsPassword: 패스워드 입력여부 설정

주요 이벤트

  • Completed: 입력이 끝났을 때(입력 후 Enter 키를 눌렀을 때) 발생
  • TextChanged: 입력 값이 바꼈을 때 발생
    • e.OldTextValue: 바뀌기 전의 값
    • e.NewTextValue: 새롭게 바뀐 값

아래 예제는 다음을 따르는 예제.

  • Chat 유형 Entry 값을 Label에 표시
  • 비밀번호를 입력이 완료되면 경고창(Alert Dialog)이 나타남

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <Entry Keyboard="Chat" Placeholder="Chat" TextChanged="Handle_TextChanged"></Entry>
        <Entry Keyboard="Default" Placeholder="Default"></Entry>
        <Entry Keyboard="Email" Placeholder="Email"></Entry>
        <Entry Keyboard="Numeric" Placeholder="Numeric"></Entry>
        <Entry Keyboard="Telephone" Placeholder="Telephone"></Entry>
        <Entry Keyboard="Text" Placeholder="Text"></Entry>
        <Entry Keyboard="Url" Placeholder="Url"></Entry>
        <Entry IsPassword="true" Placeholder="Password" Completed="Handle_Completed"></Entry>
        <Label x:Name="label"></Label>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Completed(object sender, System.EventArgs e)
        {
            DisplayAlert("Completed", "Completed!", "OK");
        }

        void Handle_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
        {
            label.Text = e.NewTextValue;
        }
    }
}

실행화면

 

에디터(Editor)

Editor는 여러 줄의 텍스트를 입력할 때 사용한다.

주요 속성

  • Text: 텍스트 값

주요 이벤트

  • Completed: 입력이 끝났을 때(입력 후 Enter 키를 눌렀을 때) 발생
  • TextChanged: 입력 값이 바꼈을 때 발생
    • e.OldTextValue: 바뀌기 전의 값
    • e.NewTextValue: 새롭게 바뀐 값

아래 예제는 Editor에 입력된 값을 Label에 그대로 출력하는 예제.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <Label x:Name="label"></Label>
        <Editor Text="asdf" x:Name="editor" BackgroundColor="Silver" VerticalOptions="FillAndExpand" TextChanged="Handle_TextChanged"></Editor>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
        {
            label.Text = e.NewTextValue;
        }
    }
}

실행화면

 

피커(Picker)

Picker는 항목을 선택할 수 있게 해주는 입력양식이다. 안드로이드에선 원하는 항목을 선택하도록 하는 팝업창이 뜨지만 iOS에서는 상하로 스와이프하여 선택하는 창이 나타난다.

주요 속성

  • Title: Picker의 제목
  • Picker.Items: Item 모음

주요 이벤트

  • SeletedIndexChanged: 선택된 Item이 변경됐을 때 발생

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <!-- 속성요소구문(Property Element Syntex)를 사용하여 Item 추가 -->
        <Picker x:Name="picker" Title="카카오 프렌즈" SelectedIndexChanged="Handle_SelectedIndexChanged">
            <Picker.Items>
                <!-- XAML에서 문자열을 사용하려면 <x:String>을 사용 -->
                <x:String>라이언</x:String>
                <x:String>어피치</x:String>
                <x:String>프로도</x:String>
            </Picker.Items>
        </Picker>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            // e 객체는 EventArgs 타입이므로 Picker의 선택된 Item 정보가 없음
            // Picker 객체로부터 선택된 Item을 직접 가져와야 함
            var selectedItem = picker.Items[picker.SelectedIndex];

            DisplayAlert("선택한 항목", selectedItem, "OK");
        }
    }
}

그런데 위의 코딩 방법은 하드 코딩(Hard Coding, 데이터를 코드 내부에 직접 입력하는 것)이다.

아래에 소개한 코드도 일단 하드 코딩이지만… 하드 코딩을 하지 않으려면 어떻게 해야 하는지에 대해 설명한다. 아래 예제는 Picker의 선택된 Item이 변경됐을 때 해당 Item의 이름이 아닌 Id 값을 출력하는 예제다.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    Padding="40"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <StackLayout>
        <!-- 속성요소구문(Property Element Syntex)를 사용하여 Item 추가 -->
        <Picker x:Name="myPicker" Title="카카오 프렌즈" SelectedIndexChanged="Handle_SelectedIndexChanged">
        </Picker>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

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

namespace MyFirstXamarinApp
{
    /* Picker에 들어갈 Item 정보 */
    public class MyPicker
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            // Picker에 Item 추가
            foreach (var pick in GetMyPicker())
                myPicker.Items.Add(pick.Name);
        }

        /* Picker의 선택된 Item이 바꼈을 때의 이벤트 처리기 */
        void Handle_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            // e 객체는 EventArgs 타입이므로 Picker의 선택된 Item 정보가 없음
            // Picker 객체로부터 선택된 Item을 직접 가져와야 함
            var name = myPicker.Items[myPicker.SelectedIndex];

            // 선택된 Item의 Id 출력
            // single(): 조건에 맞는 단일 레코드를 반환하는 LINQ 메소드
            var item = GetMyPicker().Single(cm => cm.Name == name); 
            DisplayAlert("선택한 항목", item.Id.ToString(), "OK");
        }

        /* Picker에 들어갈 IList<T> 객체 반환 */
        private IList<MyPicker> GetMyPicker()
        {
            // 하드코딩 부분. 실습을 위해 일단 하드코딩... 
            return new List<MyPicker>
            {
                new MyPicker{ Id=1, Name="라이언"},
                new MyPicker{ Id=2, Name="어피치"},
                new MyPicker{ Id=3, Name="프로도"}
            };
        }
    }
}

실행화면

 

Date and Time Picker

DatePicker와 TimePicker는 날짜 및 시간을 선택할 수 있는 Picker다.

DatePicker의 주요 속성

  • Date: 기본 날짜. 기본 형식은 “월 일 년”
  • Format: 날짜 출력형식 지정. C# 날짜 형식으로 지정 가능. YyMmDd 키워드 사용
  • MinimumDate: 지정 가능한 최소 날짜
  • MaximumDate: 지정 가능한 최대 날짜

DatePicker의 주요 이벤트

  • DateSelected: 날짜를 선택할 때 발생하는 이벤트

TimePicker의 주요 속성

  • Time: 기본 시간
  • Format: 시간 출력형식 지정. HhMmSs 키워드 사용.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>

 <!-- XAML 파서가 DateTime이 정의된 위치를 알 수 있도록 xmlns:sys를 통해 System 네임스페이스를 가져와야 함 -->
 <!-- DateTime은 mscorlib 어셈블리에 속해있음 -->
<ContentPage 
    Padding="40"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    
    <StackLayout>
        <Label Text="특정 날짜를 표시하는 Date Picker"></Label>
        <DatePicker x:Name="datePicker1" Date="1 Jan 2018" Format="yyyy년 MM월 dd일" MinimumDate="1 Jan 2018" MaximumDate="31 Dec 2018" DateSelected="Handle_DateSelected"></DatePicker>
        
        <!-- XAML 태그 확장과 x:Static을 사용하여 클래스의 정적 멤버에 접근 -->
        <Label Text="현재 날짜를 표시하는 Date Picker"></Label>
        <DatePicker x:Name="datePicker2" Date="{x:Static sys:DateTime.Today}" Format="yyyy MMM dd" DateSelected="Handle_DateSelected"></DatePicker>
        
        <Label Text="특정 시간을 표시하는 Time Picker"></Label>
        <TimePicker x:Name="timePicker1" Time="18:30:45" Format="HH시 mm분 ss초"></TimePicker>
        
        <!-- 현재 시간을 표시하는 Time Picker -->
        <!-- XAML에서 현재 시간을 표시하는 법을 모르겠다... 현재 시간을 표시하는 부분은 C# 코드로 구현 -->
        <Label Text="현재 시간을 표시하는 Time Picker"></Label>
        <TimePicker x:Name="timePicker2" Format="t"></TimePicker>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            timePicker2.Time = DateTime.Now.TimeOfDay; // timePicker2에 현재 시간 표시
        }

        void Handle_DateSelected(object sender, Xamarin.Forms.DateChangedEventArgs e)
        {
            var date = e.NewDate;
            DisplayAlert("선택한 날짜", date.ToString("yyyy년 MM월 dd일"), "OK");
        }
    }
}

실행화면

 

테이블 뷰(Table View)

TableView는 양식 또는 설정 페이지를 만드는 데 아주 유용한 도구다. Table View는 Section 단위로 구분되며 각 Section은 여러 개의 Cell을 포함한다.

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>

 <!-- TableView엔 intent라는 열거형 존재 -->
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <TableView Intent="Form">
        <TableRoot>
            <TableSection Title="Basics">
                <TextCell Text="이름" Detail="GanziBoy"></TextCell>
                <EntryCell Label="메시지" Placeholder="(메시지를 입력하세요.)" Completed="Handle_Completed"></EntryCell>
                <SwitchCell Text="알림" On="true" OnChanged="Handle_OnChanged"></SwitchCell>
            </TableSection> 
        </TableRoot>
    </TableView>
</ContentPage>

실행화면

 

Table View에 Custom Cell 추가하기

Table View에 사용자 정의 셀을 추가

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>

 <!-- TableView엔 intent라는 열거형 존재 -->
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <TableView Intent="Form">
        <TableRoot>
            <TableSection Title="Basics">
                <TextCell Text="이름" Detail="GanziBoy"></TextCell>
                <EntryCell Label="메시지" Placeholder="(메시지를 입력하세요.)" Completed="Handle_Completed"></EntryCell>
                <SwitchCell Text="알림" On="true" OnChanged="Handle_OnChanged"></SwitchCell>
                
                <!-- Custom Cell(사용자 정의 셀) -->
                <ViewCell>
                    <StackLayout Orientation="Horizontal" Padding="13, 0"><!-- Padding="가로여백, 세로여백" -->
                        <Label Text="시작일" VerticalOptions="Center"></Label>
                        <DatePicker Date="1 Jan 2018" HorizontalOptions="EndAndExpand"></DatePicker>
                    </StackLayout>
                </ViewCell>
            </TableSection> 
        </TableRoot>
    </TableView>
</ContentPage>

실행화면

 

바인딩 가능한 속성(Bindable Property)

모습이 거의 똑같은 Layout을 여러 개 배치한다고 가정해보자. 예를 들어 DatePicker를 오른쪽에 표시하고 그 왼쪽엔 설명이 각기 다른 Label을 표시하는 Layout을 여러 개 배치하려한다. XAML <Label> 태그와 <DatePicker> 태그를 쭉 복붙한 후 Label.Text 속성만 각각 다르게 작성하면 되지 않을까? 하지만 이런 경우는 중복배제(DRY, Don’t Repeat Yourself)를 지향하는 원리에 어긋난다.

이런 경우 BindableProperty 객체와 XAML 태그 확장(XAML Markup Extension)을 사용하면 코드의 중복을 방지할 수 있다. 아래 예제는 왼쪽에 Label, 오른쪽에 DatePicker를 배치하는 레이아웃을 TableView 내에 여러 개 배치하는 예제.

DateCell.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell 
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.DateCell">
    <StackLayout Orientation="Horizontal" Padding="13, 0">
        <!-- Label.Text는 LabelText라는 이름의 속성과 연결(바인딩)됨 -->
        <Label Text="{Binding LabelText}" VerticalOptions="Center"></Label>
        <DatePicker Date="1 Jan 2018" HorizontalOptions="EndAndExpand"></DatePicker>
    </StackLayout>
</ViewCell>

DateCell.xaml.cs

using Xamarin.Forms;

namespace MyFirstXamarinApp
{
    public partial class DateCell : ViewCell
    {
        /* Label.Text <--> LabelProperty <--> LabelText 상호 연결을 위한 LabelProperty 객체 생성
         * 첫번째 매개변수: 바인딩할 속성 이름(여기선 LabelText 라는 이름으로 명명함)
         * 두번째 매개변수: 바인딩할 속성의 타입 
         * 세번째 매개변수: 바인딩할 속성이 선언된 클래스의 타입 */
        public static readonly BindableProperty LabelProperty =
            BindableProperty.Create("LabelText", typeof(string), typeof(DateCell));

        /* 바인딩에 사용할 속성 */
        public string LabelText
        {
            get { return GetValue(LabelProperty) as string; }
            set { SetValue(LabelProperty, value); }
        }

        public DateCell()
        {
            InitializeComponent();

            BindingContext = this;
        }
    }
}

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    xmlns:local="clr-namespace:MyFirstXamarinApp"
    xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstXamarinApp.MainPage">
    <TableView Intent="Settings">
        <TableRoot>
            <TableSection Title="Basics">
                <TextCell Text="이름" Detail="GanziBoy"></TextCell>
                <EntryCell Label="메시지" Placeholder="(메시지를 입력하세요.)" Completed="Handle_Completed"></EntryCell>
                <SwitchCell Text="알림" On="true" OnChanged="Handle_OnChanged"></SwitchCell>
            </TableSection> 
            <TableSection Title="BindableProperty 예제">
                <local:DateCell LabelText="안녕요?ㅎ"></local:DateCell>
                <local:DateCell LabelText="Hello?"></local:DateCell>
                <local:DateCell LabelText="Hi?"></local:DateCell> 
            </TableSection> 
        </TableRoot>
    </TableView>
</ContentPage>

실행화면

 

댓글 남기기