티스토리 뷰

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

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

이 챕터는 주로 레이아웃 컨셉에 대해 설명합니다. 레이아웃은 페이지의 시각적 View들을 어떻게 배치하고 관리할지에 대한 기술이나 관련 Class에 관한 내용을 말합니다.

레이아웃은 LayoutLayout<T>를 상속한 Class와 관련이 있습니다. 이 챕터에서는 그 중에서도 StackLayout에 집중합니다.

참고
Xamarin.Forms 3.0부터 FlexLayout을 이용할 수 있습니다. FlexLayoutStackLayout과 유사하게 View를 가로 혹은 세로 방향으로 나열하는 Layout이지만, 공간이 부족하면 다음 줄로 줄내림하는 기능을 제공합니다.

이 챕터에서는 StackLayout 외에도 ScrollView, Frame, BoxView Class를 소개합니다.

스택 뷰

StackLayoutLayout<View> Class를 상속하였기 때문에 IList<View> Type의 Children Property를 상속받습니다. 따라서 다수의 자식 View를 Children 컬렉션에 추가할 수 있으며, StackLayout은 가로나 세로 방향으로 자식 View들을 나열합니다.

StackLayoutOrientation Property에는 StackOrientation Enum 값을 설정할 수 있습니다. StackOrientation Enum은 Vertical 혹은 Horizontal 값을 가지고 있습니다. Orientation Property의 기본 값은 Vertical 입니다.

StackLayoutSpacing Property는 double 값을 받으며 자식 View 사이의 간격을 조정합니다. Spacing의 기본 값은 6입니다.

C# 코드 상에서 forforeach 루프를 사용하여 StackLayoutChildren 컬렉션에 자식 View를 추가할 수 있습니다. ColorLoop 샘플에서는 foreach를 통해 Children에 자식 View를 추가하는 예제를 보여줍니다.

var colors = new[] 
{
    new { value = Color.Red, name = "Red" },
    new { value = Color.Green, name = "Green" },
    new { value = Color.Blue, name = "Blue" },
};

StackLayout stackLayout = new StackLayout();

foreach (var color in colors)
{
    stackLayout.Children.Add(
    new Label
    {
        Text = color.name,
        TextColor = color.value
    });
}

ColorList 샘플에서는 View 컬렉션 인스턴스를 생성하여 Children Property에 할당하는 예제를 보여줍니다.

StackLayout stacklayout = new StackLayout
{
    Children =
    {
        new Label
        {
            Text = "Red",
            TextColor = Color.Red
        },
        new Label
        {
            Text = "Green",
            TextColor = Color.Green
        },
        new Label
        {
            Text = "Blue",
            TextColor = Color.Blue
        }
    }
};

Children Property에는 View를 상속한 Class 인스턴스나 다른 StackLayout 인스턴스를 추가하실 수 있습니다.

콘텐트 스크롤

한 페이지에 표현할 수 없을 정도로 많은 View를 StackLayout에 추가한 경우 ScrollView를 통해 스크롤 기능을 제공할 수 있습니다.

ScrollViewContent Property에 스크롤하기 원하는 View를 추가할 수 있습니다. StackLayout 뿐만 아니라 다른 모든 종류의 View를 Content Property에 지정하여 스크롤할 수 있습니다.

ScrollViewOrientation Property에 ScrollOrientation의 Property를 지정할 수 있습니다. ScrollOrientationVertical, Horizontal, Both Property를 제공합니다. 기본 값은 Vertical 입니다. 만약 ScrollView의 자식이 StackLayout이라면, ScrollViewOrientation Property와 StackLayoutOrientation은 일치해야 합니다.

ReflectedColors 샘플은 Color 목록을 출력하기 위해 ScrollViewStackLayout을 사용하는 예제를 제공합니다. 샘플에서는 .NET Reflection을 통해 Color Struct의 public static Property와 Field를 동적으로 조회하는 방법도 소개하고 있습니다.

StackLayout stackLayout = new StackLayout();

//Color Struct의 Field를 .NET Reflection을 통해 조회
foreach (FieldInfo info in typeof(Color).GetRuntimeFields())
{
    //Obsolete(구식) Field는 조회하지 않음
    if (info.GetCustomAttribute<ObsoleteAttribute>() != null)
        continue;

    if (info.IsPublic && info.IsStatic && info.FieldType == typeof(Color))
        stackLayout.Children.Add(CreateColorLabel((Color)info.GetValue(null), info.Name));
}

//Color Struct의 Property를 .NET Reflection을 통해 조회
foreach (PropertyInfo info in typeof(Color).GetRuntimeProperties())
{
    MethodInfo methodInfo = info.GetMethod;
    if (methodInfo.IsPublic && methodInfo.IsStatic && methodInfo.ReturnType == typeof(Color))
        stackLayout.Children.Add( CreateColorLabel((Color)info.GetValue(null), info.Name));
}

Expands 옵션

StackLayout이 자식을 수직으로 배열할 때, 각 자식들은 StackLayout의 전체 높이에서 일정 부분만큼 공간을 차지하게 됩니다. StackLayout은 자식의 크기, HorizontalOptions, VerticalOptions Property 설정에 따라 자식들을 배치하게 됩니다. HorizontalOptionsVerticalOptions Property에는 LayoutOptions Struct 인스턴스를 할당할 수 있습니다.

LayoutOptions Struct는 2개의 Property를 정의하고 있습니다.

개발 편의를 위해 LayoutOptions Struct는 8개의 static read-only field를 제공하고 있습니다. 8개의 field는 LayoutOptions Type이며 AlignmentExpands의 모든 조합을 제공합니다.

Start, Center, End 외에 AndExpand 접미사로 끝나는 옵션들은 Expands 값이 true인 경우를 말합니다. 이 동작에 대해서는 아래에서 설명합니다. 아래의 설명들은 StackLayoutOrientation Property 값이 기본 값인 Vertical로 설정했을 때를 기준으로 작성되었습니다. Orientation Property 값이 Horizontal로 설정되었을 때도 규칙은 동일합니다.

수직 StackLayout에서 자식 View의 HorizontalOptions Property는 자식 View가 수평정렬되는 방향을 결정합니다. 자식 View의 HorizontalOptions Property에 Alignment(Start, Center, End) 값을 할당하면 StackLayout은 자식들을 수평으로 정렬(좌측, 가운데, 오른쪽)하며 자식들은 Unconstrained 상태가 됩니다. (Unconstrained 상태란 부모가 제공하는 공간을 채우지 않고 자신의 Content 만큼 공간을 차지하는 것을 말합니다.) Fill 값을 할당하면 자식들은 수평으로 Constrained 상태가 됩니다. (Constrained 상태란 부모가 제공한 공간을 모두 채우는 것을 말합니다.)

수직 StackLayout에서 자식들의 VerticalOptions Property의 값은 무시됩니다. 자식들은 Unconstrained 상태가 되며 Content의 높이 만큼만 공간을 차지합니다.

만약 수직 StackLayoutVerticalOptions Property를 Start, Center, End 값 중에서 하나로 할당하면 StackLayout은 Unconstrained 상태가 되고 StackLayout의 높이는 자식들의 높이 총합으로 결정됩니다.

만약 수직 StackLayoutVerticalOptions Property가 Fill 값으로 할당되면 StackLayout은 Constrained 상태가 되고 StackLayout은 부모가 제공해준 높이 전체를 차지합니다. 이 상태에서는 StackLayout의 높이가 자식들의 높이 총합보다 클 수 있습니다. 이 경우 StackLayout은 자식에게 할당하고 남은 여분의 공간을 가지게 됩니다. 여분의 공간들은 자식들의 VerticalOptions Property 값에 포함된 Expands 설정에 따라 달라집니다. VerticalOptions Property의 Expandstrue인 자식들은 남는 여분공간을 균당하게 나누어 가집니다. 따라서 자식들의 높이 총합은 StackLayout의 높이와 맞추어 집니다. 결국 Expandstrue인 자식들은 필요한 공간보다 더 큰 공간을 제공받게 되는데, 할당받은 공간 내에서 수직정렬 방향은 각자의 VerticalOptions Property 값에 따라 결정됩니다.

VerticalOptionsDemo 예제코드를 통해 이러한 설정을 시험해 볼 수 있습니다. VerticalOptionsDemo 예제코드

Frame과 BoxView

FrameBoxView는 사각형을 그리기 위해 사용되는 View입니다.

Frame View는 다른 View 주위에 사각형 박스를 그릴수 있습니다. FrameContentView를 상속하기 때문에 Content Property를 가지고 있으며, Frame 내부에 그려질 자식 View는 Content Property에 지정할 수 있습니다. Frame은 기본적으로 투명하게 출력되지만 아래 3개의 Property를 통해 외형을 설정할 수 있습니다.

  • OutlineColor Property: 외곽선 색상을 결정할 수 있습니다. 현재 플렛폼에서 사용 중인 색상 정책을 모를 경우 일반적으로 Color.Accent를 지정합니다.
  • HasShadow Property: true로 설정하면 iOS 장치에서 그림자가 나타납니다.
  • Padding Property: Thickness Type의 값을 할당하면 FrameFrameContent 사이의 여백 크기를 지정할 수 있습니다.
참고
Xamarin.Forms 3.0 부터 OutlineColor Property는 BorderColor Property로 변경되었습니다. 더불어 CornerRadius Property를 통해 외곽선의 모서리를 둥글게 표현할 수 있습니다.

FrameHorizontalOptionsVerticalOptions Property의 기본 값은 LayoutOptions.Fill 입니다. 따라서 Frame은 기본적으로 부모가 제공해주는 공간 전체를 차지합니다. 다른 값으로 설정하면 Frame의 크기는 내부 Content에 따라 달라집니다.

FramePadding 기본 값은 20입니다. 따라서 Frame은 기본적으로 20만큼의 안쪽여백을 가집니다.

FramedText 샘플 코드를 통해 Frame을 살펴보실 수 있습니다.

BoxView는 단순히 사각형을 화면에 그리며 색상은 Color Property를 통해 지정할 수 있습니다.

BoxView가 Constrained 상태면(HorizontalOptionsVerticalOptions Property가 LayoutOptions.Fill 값을 가질 경우) BoxView는 부모가 제공하는 공간을 모두 차지하게 됩니다. BoxView가 Unconstrained 상태면(HorizontalOptionsVerticalOptions Property가 Start, Center,End로 설정된 경우) BoxView는 기본적으로 가로 세로 40 만큼의 공간을 가집니다.

BoxViewWidthRequestHeightRequest Property를 지정하여 크기를 직접 결정할 수도 있습니다. 이에 대한 예제는 SizedBoxView 샘플에서 확인하실 수 있습니다.

ColorBlocks 샘플은 Frame, BoxView를 사용하여 Xamarin.Forms 색상 리스트를 출력하는 예제를 제공합니다. 색상과 색상명을 수평으로 배치하기 위해 수평 StackLayout의 자식으로 BoxViewLabel 인스턴스를 지정하였습니다. 수평 StackLayoutFrame의 자식으로 지정하여 각 색상 마다 외곽선을 표현합니다. 각 Frame들은 수직 StackLayout의 자식으로 추가하였으며 ScrollView를 통해 색상들을 스크롤 할 수 있게 하였습니다. 컬러리스트 출력하기

StackLayout에 ScrollView 추가하기

일반적으로 StackLayoutScrollView의 자식으로 배치하여 스크롤 기능을 제공하게 됩니다. 반대로 ScrollViewStackLayout의 자식으로 배치할 수 도 있습니다. StackLayout의 자식들은 Unconstrained상태(높이가 명확하게 지정되지 않은 상태로서 자신의 Content 크기 만큼 축소되는 상태)가 되기 때문에 이론적으로 ScrollViewStackLayout의 자식으로 배치해서는 안됩니다. ScrollView가 스크롤 기능을 제공하려면 반드시 Constrained상태(높이가 명확하게 지정된 상태)여야 합니다.

그러나 ScrollViewVerticalOptions Property 값을 FillAndExpand로 설정한다면 스크롤 기능을 제공할 수 있게 됩니다. 이에 관한 예제는 BlackCat 샘플에서 제공합니다.

BlackCat 샘플에서는 공통코드 Library 프로젝트에서 EmbeddedResource를 액세스 하는 방법을 제공합니다.

StackLayout textStack = new StackLayout();

//Embedded Resource 로드하기
Assembly assembly = GetType().GetTypeInfo().Assembly;
string resourcePath = "BlackCat.Texts.TheBlackCat.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourcePath))
{
    using (StreamReader reader = new StreamReader(stream))
    {
        string line;
        while (null != (line = reader.ReadLine()))
        {
            Label label = new Label { Text = line };
            textStack.Children.Add(label);
        }
    }
}

이러한 접근 방법은 Shared Asset Projects(SAPs)에서도 가능하지만 Resource의 경로를 지정하는 방법이 조금 더 까다롭습니다. SAPs에서 리소스 접근 방법은 BlackCatSap 샘플에서 제공합니다.

//SAP 프로젝트 유형에서는 리소스 경로를 플렛폼 프로젝트에 맞추어 지정해야 함
#if __IOS__
    string resource = "BlackCatSap.iOS.Texts.TheBlackCat.txt";
#elif __ANDROID__
    string resource = "BlackCatSap.Droid.Texts.TheBlackCat.txt";
#elif WINDOWS_UWP
    string resource = "BlackCatSap.UWP.Texts.TheBlackCat.txt";
#elif WINDOWS_APP
    string resource =  "BlackCatSap.Windows.Texts.TheBlackCat.txt";
#elif WINDOWS_PHONE_APP
    string resource = "BlackCatSap.WinPhone.Texts.TheBlackCat.txt";
#endif

댓글