스타일을 사용하여 일관된 UI 만들기
- 8분
.NET MAUI(다중 플랫폼 앱 UI)에서 리소스는 XAML(Extensible Application Markup Language) 마크업에서 하드 코딩된 중복 값을 방지하는 데 적합하지만 적용하기가 번거로울 수 있습니다. 각 속성 값을 개별적으로 할당하면 XAML이 복잡하고 장황해집니다. 이 단원에서는 여러 설정을 스타일 하나로 그룹화하는 방법을 설명합니다. 이 방법을 사용하면 코드를 정리하고 더 쉽게 유지 관리하는 데 도움이 됩니다.
리소스에서 XAML을 혼란스럽게 하는 방법
리소스는 단일 속성에 대한 값을 제공합니다. 그러나 많은 리소스를 사용하면 XAML이 장황해질 수 있습니다. 사용자 지정된 단추의 모양이 필요하다고 가정해 보세요. 먼저 필요한 값에 대한 리소스를 만듭니다. 그런 다음, 각 리소스를 모든 단추에 적용합니다. 다음 코드에서는 XAML 마크업에서 단추 두 개를 찾는 방법을 보여줍니다.
<Button
Text = "OK"
BackgroundColor = "{StaticResource highlightColor}"
BorderColor = "{StaticResource borderColor}"
BorderWidth = "{StaticResource borderWidth}"
TextColor = "{StaticResource textColor}" />
<Button
Text = "Cancel"
BackgroundColor = "{StaticResource highlightColor}"
BorderColor = "{StaticResource borderColor}"
BorderWidth = "{StaticResource borderWidth}"
TextColor = "{StaticResource textColor}" />
각 단추에 동일한 5개의 속성을 설정하는 방법에 주의하세요. 리소스를 사용하면 전체 중 4개에서 하드 코딩된 반복 값이 필요하지 않습니다. 그러나 이 형식의 XAML 마크업을 빠르게 읽기가 어렵습니다. 또한 컨트롤마다 수많은 속성을 설정하는 경우 해당 속성 중 하나를 실수로 생략하기 쉬우며 이로 인해 컨트롤 모양이 일치하지 않게 됩니다. 해결책은 속성 4개 모두 한 번에 할당하는 스타일을 만드는 것입니다.
setter란?
setter는 스타일을 만드는 데 사용하는 주요 구성 요소입니다.
setter는 속성/값 쌍의 컨테이너입니다. setter는 대입문을 나타내는 것으로 간주할 수 있습니다. 할당할 속성과 적용할 값을 지정합니다. 일반적으로 XAML 마크업에 Setter 개체를 만듭니다. 다음 예에서는 TextColor 속성의 Setter 개체를 만듭니다.
<Setter Property="TextColor" Value="White" />
다음 코드와 같이 setter의 값에 대한 리소스를 사용할 수 있습니다. 이 기술은 여러 setter에서 동일한 값을 사용하려는 경우에 유용합니다.
<Setter Property="TextColor" Value="{StaticResource textColor}" />
참고
setter에 지정한 속성 값은 바인딩 가능한 속성으로 구현되어야 합니다. Property 접미사로 끝나는 .NET MAUI의 컨트롤에 있는 모든 속성은 바인딩 가능한 속성입니다. setter에서 TextColor와 같은 속성을 사용하려는 경우 해당 컨트롤에 TextColorProperty라는 바인딩 가능한 해당 속성이 있는지 확인합니다. 실제로 setter에서 사용하려는 거의 모든 속성이 이 방법으로 구현됩니다.
스타일이란?
스타일은 특정 형식의 컨트롤을 대상으로 하는 setter 컬렉션입니다. setter의 속성이 해당 형식에 있는지 확인할 수 있도록 .NET MAUI에 대상 유형이 필요합니다.
다음 코드에서는 이전 예의 값 4개를 결합한 스타일을 보여줍니다. TargetType이 Button으로 설정되고 setter의 모든 속성이 Button 클래스의 구성원입니다. Label 클래스에는 BorderColor 또는 BorderWidth 속성이 포함되어 있지 않으므로 레이블에 이 스타일을 사용할 수 없습니다.
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="#2A84D3" />
<Setter Property="BorderColor" Value="#1C5F9B" />
<Setter Property="BorderWidth" Value="3" />
<Setter Property="TextColor" Value="White" />
</Style>
스타일 정의
일반적으로 ResourceDictionary 개체 내에서 스타일을 리소스로 정의합니다. 리소스 사전을 사용하면 같은 페이지에 있는 컨트롤 여러 개나 전체 애플리케이션에서 스타일을 간편하게 사용할 수 있습니다. 다음 코드에서는 사전 내에서 스타일을 리소스로 정의하는 방법을 보여줍니다. x:Key 속성을 통해 스타일 이름이 지정됩니다. 스타일 이름을 지정하면 XAML 페이지 내에서 해당 스타일을 참조할 수 있습니다.
<ContentPage.Resources>
<Style x:Key="MyButtonStyle" TargetType="Button">
...
</Style>
</ContentPage.Resources>
스타일 적용
명명된 이름을 Style 속성에 할당하여 스타일을 컨트롤에 연결합니다. 할당하면 스타일의 각 Setter 개체가 대상 컨트롤에 적용됩니다. 다음 코드에서는 단추 스타일을 단추 두 개에 적용하는 방법을 보여줍니다.
<Button Text="OK" Style="{StaticResource MyButtonStyle}" />
<Button Text="Cancel" Style="{StaticResource MyButtonStyle}" />
이전 예에서는 StaticResource 마크업 확장을 사용하여 스타일을 컨트롤에 연결했습니다. 이 기술은 런타임에 스타일을 변경할 필요가 없을 때 유용합니다. 그러나 UI를 변경해야 하는 동적 테마와 같은 항목을 구현하려면 어떻게 해야 할까요? 이 경우 DynamicResource 마크업 확장을 사용하여 스타일을 로드하면 됩니다.
<Button Text="Cancel" Style="{DynamicResource MyButtonStyle}" />
DynamicResource는 리소스 사전에서 x:Key 속성의 대체를 수신 대기합니다. 같은 x:Key 값을 사용하여 새 스타일을 ResourceDictionary에 로드하는 코드를 작성하면 새 스타일이 UI에 자동으로 적용됩니다.
여러 컨트롤에 암시적 스타일 사용
UI에 50개의 단추가 있고 모든 단추에 동일한 스타일을 적용하려고 한다고 가정해 보세요. 지금까지 알고 있는 것과 같이 각 단추의 Style 속성에 수동으로 할당해야 합니다. 이 작업이 그렇게 어렵지는 않지만 여전히 많은 시간이 걸리고 있습니다.
암시적 스타일은 x:Key 식별자를 제공하지 않고 리소스 사전에 추가하는 스타일입니다. 암시적 스타일은 지정된 TargetType 개체의 모든 컨트롤에 자동으로 적용됩니다.
다음 코드에서는 암시적 스타일로 선언된 이전 예를 보여줍니다. 이 스타일은 페이지의 모든 단추에 적용됩니다.
<ContentPage.Resources>
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderColor" Value="Navy" />
...
</Style>
</ContentPage.Resources>
중요합니다
암시적 스타일을 컨트롤에 일치시키려면 지정된 TargetType과 정확하게 일치해야 합니다. 대상 유형에서 상속받는 컨트롤은 스타일을 받지 않습니다. 상속된 컨트롤에 영향을 주려면 스타일을 정의할 때 Style.ApplyToDerivedTypes 특성을 True로 설정하면 됩니다. 예를 들어 스타일을 Button 형식에 적용하고 Button에서 상속하는 단추(예: ImageButton, RadioButton 또는 만든 사용자 지정 형식)에 영향을 주려면 다음과 같은 스타일을 사용하면 됩니다.
<ContentPage.Resources>
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="Black" />
</Style>
</ContentPage.Resources>
스타일 재정의
스타일을 컨트롤에 설정된 기본값을 제공하는 것으로 생각할 수 있습니다. 기존 스타일이 요구 사항에 가까울 수 있지만 원하지 않는 한 두 개의 setter가 포함되어 있습니다. 이 경우 스타일을 적용한 다음 속성을 직접 설정하여 값을 재정의할 수 있습니다. 명시적 설정은 스타일 뒤에 적용되므로 스타일의 값을 재정의합니다.
페이지의 여러 단추에 다음 스타일을 사용하려고 한다고 가정해 보세요.
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderRadius" Value="10" />
<Setter Property="BorderWidth" Value="3" />
</Style>
이 스타일은 빨간색 배경이 필요한 모든 단추(취소 단추 제외)에서 작동합니다. BackgroundColor 속성을 직접 설정하는 한 취소 단추에 같은 스타일을 사용할 수 있습니다. 다음 코드에서는 색 설정을 재정의하는 방법을 보여 줍니다.
<Button
Text="Cancel"
Style="{StaticResource MyButtonStyle}"
BackgroundColor="Red"
... />
상위 항목 형식의 대상 지정
단추 및 레이블에 대한 사용자 지정 배경색을 원한다고 가정해 보세요. 형식마다 스타일을 별도로 만들거나 TargetType이 VisualElement로 설정된 스타일 하나를 만들 수 있습니다. 이 기술은 VisualElement가 Button과 Label 모두의 기본 클래스이므로 작동합니다.
다음 코드에서는 두 개의 서로 다른 두 파생 형식에 적용되는 기본 클래스를 대상으로 하는 스타일을 보여 줍니다.
<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor" Value="#2A84D3" />
</Style>
...
<Button Style="{StaticResource MyVisualElementStyle}" ... />
<Label Style="{StaticResource MyVisualElementStyle}" ... />
이 예에서는 x:Key를 사용하여 스타일을 식별하며 컨트롤에서 명시적으로 적용합니다. 여기서는 암시적 스타일의 TargetType이 컨트롤 형식과 정확하게 일치해야 하므로 암시적 스타일이 작동하지 않습니다.
BasedOn을 사용하여 스타일에서 상속
응집력 있는 UI 모양을 만들려고 한다고 가정해 보세요. 모든 컨트롤에서 일관된 배경색을 사용해야 한다고 결정합니다. 배경색 설정이 둘 이상의 스타일로 나타날 수 있습니다. 다음 코드에서는 반복되는 setter가 있는 두 가지 스타일을 보여 줍니다.
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderColor" Value="Navy" />
<Setter Property="BorderWidth" Value="5" />
</Style>
<Style x:Key="MyEntryStyle" TargetType="Entry">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="TextColor" Value="White" />
</Style>
스타일 상속을 사용하여 중복 setter를 기본 스타일로 추출할 수 있습니다. 파생 스타일을 만들려면 BasedOn 속성에서 기본 스타일을 참조하도록 설정합니다. 새 스타일은 기본 스타일에서 모든 setter를 상속합니다. 또한 파생 스타일에서 새 setter를 추가하거나 상속된 setter를 다른 값이 포함된 setter로 대체할 수 있습니다.
다음 코드에서는 계층 구조로 리팩터링된 이전 스타일 예제를 보여 줍니다. 일반적인 setter는 반복되지 않고 기본 스타일에만 나타납니다. StaticResource 마크업 확장을 사용하여 기본 스타일을 조회합니다. 이 상황에서는 DynamicResource를 사용할 수 없습니다.
<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor" Value="Blue" />
</Style>
<Style x:Key="MyButtonStyle" TargetType="Button" BasedOn="{StaticResource MyVisualElementStyle}">
<Setter Property="BorderColor" Value="Navy" />
<Setter Property="BorderWidth" Value="5" />
</Style>
<Style x:Key="MyEntryStyle" TargetType="Entry" BasedOn="{StaticResource MyVisualElementStyle}">
<Setter Property="TextColor" Value="White" />
</Style>
기본 및 파생 스타일의 TargetType 값이 호환되어야 합니다. 스타일이 호환되려면 스타일에 동일한 TargetType 속성이 있거나 파생 스타일의 TargetType이 기본 스타일의 TargetType 하위 항목이어야 합니다.