티스토리 뷰

반응형
이 포스트의 내용은 Summary of Chapter 2. Anatomy of an app (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/creating-mobile-apps-xamarin-forms/summaries/chapter02)을 번역한 자료입니다. 한글로 표현하기 어색하거나 모호한 문장은 임의로 조정하거나 삭제하였으므로 필요한 경우 원문을 참고하시기 바랍니다. 또한 언제든지 원저자의 요청에 의해 게시물이 내려지거나 수정될 수 있음을 알려드립니다. 마지막으로 이 글은 개인적인 학습목적으로 번역한 자료이며, 따라서 오역이나 잘못된 해석이 포함되어 있을 수 있으며 이로인한 어떠한 일체의 보장을 하지 않습니다.

이 문서에서는 다음 주제를 다룹니다.

참고
이 페이지에서  참고 영역은  Xamarin.Forms 책의 내용에서 달라진 부분이 무엇인지 기술하고 있습니다.

Xamarin.Forms에서 스크린을 차지하는 객체들은 Visual Element라고 합니다. Visual Element들은 VisualElement 클래스에 의해 캡슐화되어 있습니다.Visual Element들은 아래와 같은 3가지 유형으로 구분할 수 있습니다.

Page 유형에 속하는 파생 클래스들은 화면 전체를 차지하거나, 대부분의 화면을 차지하게 됩니다. Page 파생 클래스들은 Layout 파생 클래스들을 자식 Visual Element로 취합니다. Layout 파생 클래스들은 다른 Layout 혹은 View 파생 클래스들을 자식 Visual Element로 취합니다. View 파생 클래스들은 텍스트, 비트맵, 슬라이더, 버튼, 리스트 박스 등등 이 있습니다.

이 챕터에서는 텍스트를 출력하는 Label 클래스에 초점을 두고 어떻게 앱을 생성할 수 있는지에 설명을 진행할 예정입니다.

Hello 앱 만들기

Xamarin 플렛폼을 설치하면 Visual Studio 또는 Visual Studio for Mac을 통해 Xamarin.Forms 솔루션을 생성할 수 있습니다. Hello 솔루션은 공통 코드를 위해 Portable Class Library(PCL)을 사용합니다.

참고
Portable Class Library는 .NET Standard Library로 대체되었습니다. 이 책에서 모든 샘플코드는 .NET Standard Library로 변경되었습니다.

Hello 솔루션은 Visual Studio에 의해 생성된 Xamarin.Forms 솔루션이며 어떠한 수정도 되지 않은 상태입니다. 이 솔루션은 6개의 프로젝트로 구성되어 있습니다.

  • Hello: Portable Class Library (PCL) 프로젝트이며 다른 Application 프로젝트에 의해 공유되는 공통코드가 위치합니다.
  • Hello.Droid: Android를 위한 Application 프로젝트
  • Hello.iOS: iOS를 위한 Application 프로젝트
  • Hello.UWP: Uiversal Windows Platform (UWP)를 위한 Application 프로젝트 (Windows 10과 Windows Mobile)
  • Hello.Windows: Windows 8.1을 위한 Application 프로젝트
  • Hello.WinPhone: Windows Phone 8.1을 위한 Application 프로젝트
참고
Xamarin.Forms는 Windows 8.1, Windows Phone 8.1, Windows 10 MObile를 지원하지 않습니다. 반면에 Xamarin.Forms는 Windows 10 데스크톱 어플리케이션 개발은 여전히 지원합니다.

처음 프로젝트를 생성하면 이러한 기본 프로젝트들이 생성된 것을 볼 수 있습니다. 이러한 프로젝트들은 해당 시뮬레이터나 모바일 장치에서 즉시 실행하실 수 있습니다.

대부분의 Xamarin.Forms 프로그램 개발에서 Application 프로젝트를 직접 수정하는 경우는 없을 것입니다. 대부분의 경우 Application 프로젝트는 프로그램을 실행하기 위한 간단한 코드로 구성될 것입니다. 그리고 대부분의 코드는 공통코드를 위한 PCL 프로젝트에 작성하게 될것입니다.

파일 내부 살펴보기

Hello 프로그램을 실행했을 때 나타나는 Visual Element는 App 생성자에 정의되어 있습니다. App은 Xamarin.Forms의 Application 클래스를 상속합니다.

참고
Visual Studio 솔루션 템플릿에 의해 생성되는 Xamarin.Forms 페이지는 XAML 파일로 구성될 것입니다. 이 책에서 XAML 파일은 Chapter 7 부터 다루어지게 될 것입니다.

Hello PCL 프로젝트의 References 부분을 살펴보면 다음의 Xamarin.Forms 어셈블리를 포함하고 있습니다.

  • Xamarin.Forms.Core
  • Xamarin.Forms.Xaml
  • Xamarin.Forms.Platform

PCL프로젝트를 제외한 나머지 5개의 Application Project의 References를 살펴보면 다음 어셈블리들을 추가적으로 포함하고 있습니다.

  • Xamarin.Forms.Platform.Android
  • Xamarin.Forms.Platform.iOS
  • Xamarin.Forms.Platform.UWP
  • Xamarin.Forms.Platform.WinRT
  • Xamarin.Forms.Platform.WinRT.Tablet
  • Xamarin.Forms.Platform.WinRT.Phone
참고
최근에 생성된 Xamarin.Forms 프로젝트는 References 하위에 어셈블리가 나타나지 않을 수 있습니다. 대신 PackageReference 태그가 Xamarin.Forms NuGet 패키지를 참조하고 있을 것입니다. Visual Studio Reference를 살펴보면 Xamarin.Forms 어셈블리 대신 Xamarin.Forms 패키지들이 나타날 것입니다.

각각의 Application Project를 살펴보면 Xamarin.Forms 네임스페이스에 포함된 Forms.Init() 정적메서드를 호출하고 있을 것입니다. Forms.Init 메서드는 Xamarin.Forms 라이브러리를 초기화합니다. 각각의 Application Project에는 서로 다른 버전의 Forms.Init가 정의되어 있을 것입니다. Xamarin.Android는 Xamarin.Forms.Platform.Android에 포함된 Forms.Init()를 호출하며 Xamarin.iOS는 Xamarin.Forms.Platform.iOS에 정의된 Forms.Init()를 호출합니다. Forms.Init()는 아래 파일에 포함되어 있습니다.

각 Application 프로젝트는 PCL프로젝트의 App 클래스 인스턴스를 생성할 것입니다. 이 코드는 LoadApplication() 메서드 호출과 함께 나타나며 아래 클래스에 존재합니다.

대부분의 Application 프로젝트는 LoadApplication(new App()) 호출을 제외하고 아무 것도 하지 않습니다.

PCL과 SAP

Xamarin.Forms 솔루션에서 공통코드 작성을 위해 Portable Class Library (PCL) 또는 Shared Asset Project 중에서 선택하실 수 있습니다. SAP 솔루션을 생성하시려면 Visual Studio에서 프로젝트를 생성하실 때 Code Sharing Sterategy에서 Shared Project를 선택하시면 됩니다. HelloSap 솔루션은 SAP  템플릿으로 생성된 프로젝트를 보여줍니다.

참고
Portable Clasds Library는 .NET Standard Library로 대체되었습니다. 이 책에서 모든 샘플코드는 .NET Standard Library로 변경되었습니다. PCL과 .NET Standard Library는 개념상으로 매우 유사하기 때문에 큰 변화가 있는 것은 아닙니다.

PCL은 공통코드를 라이브러리로 만들고 각 플렛폼 Application Project가 참조하는 형태로 접근합니다. SAP는 사실상 공통코드를 모든 플렛폼 Application Project에 위치시키는 형태의 접근법입니다.

대부분의 Xamarin.Forms 개발자들은 PCL 접근법을 선호합니다. 이 책에서도 대부분의 솔루션은 PCL 접근법을 사용합니다. SAP를 사용하는 경우 Sap 접미사가 프로젝트 명에 포함되게 됩니다.

SAP를 사용하는 경우 플렛폼 별로 다른 코드가 실행되도록 공통코드를 작성할 수 있습니다. C#전처리기(if, #elif, #endif)와 아래의 사전정의된 구분자를 조합함으로써 플렛폼 별로 다른 코드를 실행할 수 있습니다.

  • iOS: __IOS__
  • Android: __ANDROID__
  • UWP: WINDOWS_UWP

PCL이나 SAP나 공통코드 프로젝트에서는 런타임에 어떤 플렛폼이 실행 중인지 식별할 수 있으며, 이를 통해 서로 다른 코드를 실행할 수 있습니다.

텍스트를 위한 Label

Greeting 솔루션은 Greeting 프로젝트에 C#파일을 어떻게 추가할 수 있는지 보여줍니다. 추가된 C#파일은 GreetingPage라는 이름의 Class를 정의하고 있으며 ContentPage를 상속하고 있습니다. 이 책에서 대부분의 프로젝트는 ContentPage를 상속한 Class를 1개를 포함하고 있으며 Class 이름은 프로젝트 이름에 Page 접미사를 붙인 형태로 작성되어 있습니다.

GreetingPage 생성자는 Label View 인스턴스를 생성하고 있습니다. Label View는 Xamarin.Forms에서 텍스트를 출력하기 위한 View입니다. Label View의 Text Property는 출력될 텍스트를 결정합니다. 이 프로그램은 ContentPage의 Content Property에 Label을 할당하고 있습니다. App Class의 생성자는 GreetingPage 인스턴스를 생성하고 MainPage Property에 할당하고 있습니다.

프로그램을 실행하면 텍스트가 좌측 상단에 나타나게 됩니다. iOS에서는 텍스트가 상태바와 겹쳐 나타나게 됩니다. 이러한 문제를 해결하는 방법은 여러가지가 있습니다.

해결책1. Page의 Padding을 지정하는 방법

Page의 Padding 속성을 지정하는 방법이 있습니다. Padding은 Thickness Type으로서 4개의 Property를 가집니다.

Padding은 Page 안쪽 여백을 지정하는 것이므로 Label이 상태바와 겹쳐지는 문제를 해결할 수 있습니다. iOS 상태바의 높이는 20이므로 상단 Padding에 20을 지정하면 됩니다.

namespace GreetingsSap
{
    public class GreetingsSapPage : ContentPage
    {
        public GreetingsSapPage()
        {
            Content = new Label { Text = "Greetings, Xamarin.Forms!" };

            //iOS의 상태바는 20의 높이를 가짐
            Padding = new Thickness(0, 20, 0, 0); 
        }
    }
}

프로그램을 실행하면 iOS에서 겹칩 문제는 해결되었지만 다른 플렛폼에서는 상단 여백이 불필요하게 크게 나타남을 알수 있습니다.

해결책2: iOS일 때만 Padding을 지정하는 방법 (SAP만 사용가능한 방법)

SAP 프로젝트에서는 C# 전처리기를 통해 iOS에서만 Padding이 지정되게 할 수 있습니다. 이러한 접근법은 GreetingSap 솔루션에서 보여주고 있습니다.

namespace GreetingsSap
{
    public class GreetingsSapPage : ContentPage
    {
        public GreetingsSapPage()
        {
            Content = new Label { Text = "Greetings, Xamarin.Forms!" };

            #if __IOS__
            //iOS의 상태바는 20의 높이를 가짐
            Padding = new Thickness(0, 20, 0, 0); 
            #endif
        }
    }
}

해결책 3: iOS일 때만 Padding을 지정하는 방법 (SAP, PCL 모두 사용가능)

이 책에서 사용된 Xamarin.Forms의 버전에서는 Device.OnPlatform이나 Device.OnPlatform<T> Static 메서드를 사용하여 iOS일 때만 Padding을 지정할 수 있습니다. 하지만 이 메서드들은 현재 Deprecated 되었습니다.

//Device.OnPlatform<T> 사용 예시
Padding = Device.OnPlatform<Thickness>(new Thickness(0, 20, 0, 0), new Thickness(0), new Thickness(0));

//Device.OnPlatform 사용 예시1 (Thickness)
Padding = Device.OnPlatform(new Thickness(0, 20, 0, 0), new Thickness(0), new Thickness(0));

//Device.OnPlatform 사용 예시2 (Int)
Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0); 

//Device.OnPlatform 사용 예시3 (Action)
Device.OnPlatform(iOS: () => { Padding = new Thickness(0, 20, 0, 0); });

Device.OnPlatform 메서드는 특정 플렛폼에서만 코드를 실행하거나 값을 지정할 수 있게 해줍니다. 내부적으로 Device.OS Static Read-only Property를 사용하고 있으며, Device.OSTargetPlatform Enum값을 반환합니다.

Device.OnPlatform 메서드, Device.OS Property, TargetPlatform Enum은 현재 모두 Deprecated되었습니다. 대신 Device.RuntimePlatform Property를 사용할 수 있습니다. Device.RuntimePlatform은 아래와 같은 문자열을 반환합니다.

  • iOS 플렛폼: "iOS" 문자열
  • Android 플렛폼: "Android" 문자열
  • UWP(Universal Windows Platform): "UWP" 문자열

Device.Idiom Static Read-only Property은 실행 중인 플렛폼의 종류를 반환합니다. Device.Idiom은 아래와 같은 TargetIdiom 값을 반환합니다.

iOS와 Android에서 Tablet, Phone를 구분하는 기준은 스크린의 Width가 600 Unit 넘는지에 따라 결정됩니다. Windows 플렛폼에서 Desktop는 UWP 프로그램이 Windows 10 데스크톱 환경에서 실행 중임을 가리키며, Phone는 UWP 앱이 Windows 10 모바일 장치에서 실행됨을 가리킵니다.

해결책 3a. Label에 Margin주기

Margin Property는 이 책이 작성된 이후에 소개되었으며 따라서 이책에는 포함되어 있지 않습니다. Margin Property도 Thickness 값을 받으며 Label의 외부 여백을 지정할 수 있습니다.

Padding Property는 Layout과 Page 파생 Class에서만 이용할 수 있습니다. Margin Property는 모든 View 파생 Class에서 이용하실 수 있습니다.

해결책 4. 페이지에서 레이블 가운데 정렬

Label을 Page의 정가운데 위치시키거나 좌측 상단이 아닌 다른 곳에 위치시키는 방법이 있습니다. Label의 HorizontalOptions, VerticalOptions Property를 사용하면 Label이 페이지에서 정렬되는 위치를 정의할 수 있습니다. HorizontalOptions, VerticalOptions Property은 LayoutOptions 구조체를 사용합니다. LayoutOptions 구조체는 아래와 같은 2개의 Property를 가집니다.

  • Alignment Property: LayoutAlignment Type으로서 4개의 Enum값을 지정할 수 있습니다.
    1. Start: 좌측 혹은 상단을 가리킴
    2. Center: 가운데를 가리킴
    3. End: 우측 혹은 하단을 가리킴
    4. Fill: 공간을 가득 채우도록 함
  • Expands Property: bool 값을 받으며 공간이 남을 경우 빈공간을 차지할 지 여부를 가리킵니다.

일반적으로 위의 두 Property를 개별적으로 직접 사용하지는 않습니다. 대신 위의 두 Property를 조합하여 8개의 Read-only static Property를 제공하는 LayoutOptions를 사용하게 됩니다.

HorizontalOptions와 VerticalOptions는 Xamarin.Forms 레이아웃 시스템에서 가장 중요한 속성이며 Chapter 4. Scrolling the Stack에서 자세히 다룹니다.

아래는 Label의 HorizontalOptions와 VerticalOptions를 LayoutOptions.Center로 지정했을 때 결과 화면입니다.

해결책 5. Label에서 텍스트 가운데 정렬

Label의 HorizontalTextAlignmentVerticalTextAlignment Property를 통해서도 텍스트의 정렬위치를 결정할 수 있습니다. HorizontalTextAlignment, VerticalTextAlignment는 TextAlignment Enum 값을 가집니다.

  • Start: 좌측 혹은 상단을 의미
  • Center: 가운데를 의미
  • End: 우측 혹은 아래쪽을 의미

HorizontalAlignment와 VerticalAlignment Property는 View에 정의되어 있지만, HorizontalTextAlignment와 VerticalTextAlignment Property는 Label에 의해서 정의되어 있습니다. 시각적인 효과는 비슷해보이지만 전자는 Label View의 배치 방향을 설정하고 후자는 Label 내부의 텍스트 정렬방향을 설정합니다. 이 내용은 다음 챕터에서 더 자세히 다룹니다.

댓글