전체 페이지뷰

2017년 2월 17일 금요일

Chapter 4. Scrolling the stack, part 3

Frame and BoxView

이 두개의 사각형 뷰는 프레젠테이션용으로 매우 유용합니다.

BoxView는 내부가 채워진 사각형입니다. View에서 파생되며, Color 속성을 정의합니다(기본 설정은 Color.Default이며 투명한 색입니다).

Frame은 내용을 둘러싸는 사각형의 테두리입니다. FrameContentView를 통해 Layout으로부터 파생되고, 그 ContentViewContent 속성을 상속받습니다. Frame의 내용은 단일 view일수도 있으며 여러 개의 view로 이루어진 레이아웃일 수도 있습니다. FrameVisualElement로부터  BackgroundColor 속성을 상속받는데 iPhone에서는 흰색이고, Android 및 Windows Phone에서는 투명합니다. 또한 Layout으로부터 Padding 속성을 상속받는데 모든 면에 20unit으로 초기화되어 여백을 줍니다. Frame은 또 HasShadow라는 속성(기본값은 true이지만 iPhone에서만 표시됨)과 OutlineColor라는 속성을 정의합니다. OutlineColor의 기본값은 투명이지만, 언제나 검은색인 iOS shadow에 영향을 미치진 않습니다.

FrameBoxView 공히 기본값이 투명이므로 색을 표현하지 않고는 잘 보이지 않을 수 있습니다. Color.Accent를 사용하면 색에 관계없이 눈에 보이게 되고, 혹은 아예 배경색을 표현할 수도 있습니다.

BoxView 또는 Frame의 크기가 제한적이지 않은 경우 (즉, StackLayout 내에 놓여있지 않고, HorizontalOptionsVerticalOptionsLayoutOptions의 기본값으로 설정된 경우) 이 둘의 크기는 컨테이너를 채울때까지 확장됩니다.

FrameContent 속성으로 Label을 화면 가운데에 지정한 프로그램의 예를 보겠습니다.
public class FramedTextPage : ContentPage
{
    public FramedTextPage()
    {
        Padding = new Thickness(20);
        Content = new Frame
        {
            OutlineColor=Color.Accent,
            Content=new Label
            {
                Text="I've been framed!",
                FontSize=Device.GetNamedSize(NamedSize.Large,typeof(Label)),
                HorizontalOptions=LayoutOptions.Center,
                VerticalOptions=LayoutOptions.Center
            }
        };
    }
}
cs

LabelFrame에서 중앙에 위치했지만, Frame이 전체 page를 채우고 있습니다. 만약 20의 Padding을 주지 않았다면 Frame이 명확히 어디에 위치했는지도 몰랐을 수 있습니다.



가운데에 프레임된 텍스트를 출력하려면 Label이 아니라 FrameHorizontalOptionsVerticalOptionsLayoutOptions.Center로 설정해 줍니다.

public class FramedTextPage : ContentPage
{
    public FramedTextPage()
    {
        Padding = new Thickness(20);
        Content = new Frame
        {
            OutlineColor = Color.Accent,
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center,
            Content = new Label
            {
                Text = "I've been framed!",
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
            }
        };
    }
}
cs

이제 Frame이 20 unit의 공백을 두고 가운데에서 텍스트를 둘러싸고 있습니다.


다음과 같이 색상도 자유로이 바꿀 수 있습니다.
public class FramedTextPage : ContentPage
{
    public FramedTextPage()
    {
        BackgroundColor = Color.Aqua;
        Padding = new Thickness(20);
        Content = new Frame
        {
            OutlineColor = Color.Black,
            BackgroundColor = Color.Yellow,
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center,
            Content = new Label
            {
                Text = "I've been framed!",
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                FontAttributes = FontAttributes.Italic,
                TextColor = Color.Blue
            }
        };
    }
}
cs




이제 다음과 같이 BoxViewContentPageContent 속성으로 설정해 봅시다.
public class SizedBoxViewPage : ContentPage
{
    public SizedBoxViewPage()
    {
        Content = new BoxView
        {
            Color = Color.Accent
        };
    }
}
cs

눈에 보이도록 Color.Accent로 설정해 주었습니다. BoxView 역시 Frame처럼 디폴트로 전체 컨테이너를 가득 채웁니다.

iOS의 경우는 상태바의 아래까지 다 채웠습니다.

이제 BoxViewHorizontalOptionsVerticalOptionsFill 말고 다른 것으로 바꿔줍니다.
public class SizedBoxViewPage : ContentPage
{
    public SizedBoxViewPage()
    {
        Content = new BoxView
        {
            Color = Color.Accent,
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center           
        };
    }
}
cs

이렇게 코딩하면 BoxView는 자신의 default 사이즈를 40unit으로 설정합니다.

BoxViewWidthRequestHeightRequest 속성이 40으로 초기화 되기 떄문입니다. 두 속성은 조금 설명이 필요합니다.

VisualElementWidth, Height의 속성을 정의하는데 읽기 전용입니다. 덧붙여서 settable, gettable한 WidthRequest, heightRequest도 정의합니다. 보통 이 속성은 -1(정의되지 않았다는 뜻)으로 설정되는데, 어떤 View 파생클래스-예를 들어 BoxView같은-는 특별한 값으로 WidthRequest, HightRequest를 지정합니다.

페이지가 하위의 레이아웃을 구성하고 모든 비주얼을 렌더링 한 후, WidthHeight 속성은 각 뷰의 실제 크기 (화면에서 뷰가 차지하는 영역)를 나타냅니다. WidthHeight는 읽기전용이므로 정보제공의 목적으로만 사용됩니다(5장에서 자세히 다룹니다).

만약 뷰를 특정 크기로 지정하고 싶다면, WidthRequestHeightRequest속성을 조절합니다. 그러나 이름에서 알 수 있듯이 이 속성은 "요청" 또는 "선호"크기일 뿐이어서, 뷰가 컨테이너를 채우는 설정이 있다면 무시됩니다.

BoxViewOnSizeRequest 메서드를 오버라이딩하여 기본 크기를 40으로 설정합니다. BoxView에서 페이지를 채울 수 있게 되면 WidthRequestHeightRequest가 무시된다는 것을 이미 보았습니다. HorizontalOptionsLayoutOptions.Left, Center 또는 Right로 설정된 경우, 또는 BoxView가 가로 StackLayout의 자식 인 경우 WidthRequest가 실행됩니다. HeightRequest도 유사합니다.

이번 챕터에 배운 코드가 들어간 새로운 SizedBoxView 프로그램을 보여드리겠습니다.

public class SizedBoxViewPage : ContentPage
{
    public SizedBoxViewPage()
    {
        BackgroundColor = Color.Pink;
        Content = new BoxView
        {
            Color = Color.Navy,
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center,
            WidthRequest = 200,
            HeightRequest = 100
        };
    }
}
cs

이제 BoxView는 정확한 크기와 색을 가지게 됩니다.

좀 더 다양한 칼라 리스트를 가지고서 FrameBoxView를 사용해 봅시다. 아래 ColorBlocks 프로그램은 ReflectedColors의 페이지 생성자와 동일한 페이지 생성자를 사용합니다, 대신 CreateColorLabel 대신 CreateColorView라는 메서드를 호출한다는 점이 다릅니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Reflection;
 
using Xamarin.Forms;
 
namespace ColorBlocksPlus
{
    public class ColorBlocksPage : ContentPage
    {
        public ColorBlocksPage()
        {
            StackLayout stackLayout = new StackLayout();
            
            // Color structure의 필드를 loop
            foreach (FieldInfo info in typeof(Color).GetRuntimeFields())
            {
                // 필요없는 색상(예를 들어 철자가 틀린 색상)은 스킵
                if (info.GetCustomAttribute<ObsoleteAttribute>() != null)
                    continue;
                if (info.IsPublic &&
                    info.IsStatic &&
                    info.FieldType == typeof(Color))
                {
                    stackLayout.Children.Add(CreateColorView((Color)info.GetValue(null), info.Name));
                }
            }
            // Color structure의 property loop
            foreach (PropertyInfo info in typeof(Color).GetRuntimeProperties())
            {
                MethodInfo methodInfo = info.GetMethod;
                if (methodInfo.IsPublic &&
                    methodInfo.IsStatic &&
                    methodInfo.ReturnType == typeof(Color))
                {
                    stackLayout.Children.Add(CreateColorView((Color)info.GetValue(null), info.Name));
                }
            }
            Padding = new Thickness(5, Device.OnPlatform(2055), 55);
            // ScrollView에 StackLayout을 넣음
            Content = new ScrollView
            {                
                Content = stackLayout
            };
        }
        View CreateColorView(Color color, string name)
        {
            return new Frame
            {
                OutlineColor = Color.Accent,
                Padding = new Thickness(5),
                Content = new StackLayout
                {
                    Orientation = StackOrientation.Horizontal,
                    Spacing = 15,
                    Children =
                    {
                        new BoxView
                        {
                            Color=color
                        },
                        new Label
                        {
                            Text=name,
                            FontSize=Device.GetNamedSize(NamedSize.Large,typeof(Label)),
                            FontAttributes=FontAttributes.Bold,
                            VerticalOptions=LayoutOptions.Center,
                            HorizontalOptions=LayoutOptions.StartAndExpand
                        },
                        new StackLayout
                        {
                            Children=
                            {
                                new Label
                                {
                                    Text=String.Format("{0:X2}-{1:X2}-{2:X2}",
                                    (int)(255*color.R),
                                    (int)(255*color.G),
                                    (int)(255*color.B)),
                                    VerticalOptions=LayoutOptions.CenterAndExpand,
                                    IsVisible= color!=Color.Default
                                },
                                new Label
                                {
                                    Text=String.Format("{0:F2}-{1:F2}-{2:F2}",
                                    color.Hue,
                                    color.Saturation,
                                    color.Luminosity),
                                    VerticalOptions=LayoutOptions.CenterAndExpand,
                                    IsVisible=color!=Color.Default
                                }
                            },
                            HorizontalOptions=LayoutOptions.End
                        }
                    }
                }
            };
        }
    }
}
 
cs

CreateColorView 메서드는 색상을 나타내는 BoxView,색상 이름을 나타내는 Label, 그리고 또 하나의 Stacklayout(RGB 컴포지션과 Hue, Saturation, Luminosity값을 출력하는 두 개의 Label 뷰로 이루어진)으로 구성된 Frame을 반환합니다. RGB 및 HSL 디스플레이는 Color.Default에서는 의미가 없으므로 내부 StackLayoutIsVisible 속성은 false로 설정되고, StakLayout은 여전히 존재하나 렌더링 시에 무시됩니다.

이 프로그램은 위의 세 개의 color 아이템의 높이를 결정하는 것이 어떤 요소인지 알수가 없으므로 모든 Label 뷰를 전부 중앙에 위치시킵니다. 보시다시피, BoxView는 텍스트의 높이를 수용하기 위해 높이가 확장됩니다.


처음으로 좀 자부심을 가질 만한 스크롤 프로그램이 만들어졌습니다.


댓글 없음:

댓글 쓰기