오늘도 더 나은 코드를 작성하였습니까?

Android Styling: themes overlay 본문

Android Material Design

Android Styling: themes overlay

hik14 2022. 10. 27. 19:13

실제로 테마를 사용하는 방법, 앱에 테마를 적용하는 방법 및 테마를 구축하는 방법에 대한 의미에 중점을 둘 것입니다.

 

Scope

Activity가  ViewGroups를 포함하고ViewGroups이 View 등을 포함하는 Tree형태를 보여줍니다.

트리의 모든 수준에서 테마를 지정하면 상위 노드에서 하위 노드로 계단식으로 연결됩니다.

ViewGroup에 테마를 설정하면 그 안의 모든 View에 적용됩니다(단일 보기에만 적용되는 스타일과 대조적으로)

 

트리의 모든 수준에서 테마를 설정해도 현재 적용 중인 테마가 대체되지 않고 오버레이됩니다.

 

자신도 테마를 지정하지만 부모도 테마를 지정하는 다음 버튼을 살펴보자

<!-- Copyright 2019 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 -->
<ViewGroup …
  android:theme="@style/Theme.App.Foo">
  <Button …
    android:theme="@style/Theme.App.Bar"/>
</ViewGroup>

속성이 두 테마 모두에 지정되면 가장 직접적으로 적용된 것, 즉 Bar에 있는 것이 버튼에 적용됩니다.

테마 Foo에 지정되었지만 테마 Bar에 지정되지 않은 모든 속성은 버튼에도 적용됩니다.

 

이것은 인위적인 예처럼 보일 수 있지만, 이 방법은 밝은 화면에서 Dark App bar과 같이 다른 모양으로 앱의 하위 섹션을 스타일링하는 데 매우 유용합니다. 그러나 관련 콘텐츠를 표시하는 하단 섹션에는 파란색 테마가 있습니다.

 

 blue section의 루트에 테마를 설정하여 달성할 수 있으며,  그 안에 있는 모든 View에 계단식으로 적용됩니다.

 

Overly Overlaid

테마가 트리의 상위에 있는 테마를 오버레이하므로 유지하려는 속성을 실수로 대체하지 않도록 테마가 지정하는 사항을 고려하는 것이 중요합니다.

 

예를 들어 View 배경색(보통 colorSurface로 제어됨)을 변경하고 싶지만 현재 테마의 나머지 부분은 유지하고 싶을 수 있습니다.

이것을 달성하기 위해 테마 오버레이라는 기술을 사용할 수 있습니다.

 

이들은 다른 테마를 오버레이하도록 설계된 테마입니다.

가능한 Scope가 작습니다. 즉, 가능한 한 적은 수의 속성만 정의(또는 상속)합니다.

사실, 테마 오버레이는 종종(항상 그런 것은 아니지만) 부모가 없습니다. 

<!-- Copyright 2019 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 -->
<style name="ThemeOverlay.MyApp.DarkSurface" parent="">
  <item name="colorSurface">#121212</item>
</style>

테마 오버레이는 다른 테마를 오버레이하도록 설계된 가능한 한 적은 수의 속성을 정의하는 좁은 범위의 테마입니다.

 

관례에 따라 "themeOverlay"로 시작하는 이름을 지정합니다.

MDC(및 AppCompat)에서 제공하는 여러 가지 편리한 테마 오버레이를 사용하여 앱 하위 섹션의 색상을 밝은 색에서 어두운 색으로 뒤집는 데 사용할 수 있습니다.

 

  • ThemeOverlay.MaterialComponents.Dark
  • ThemeOverlay.MaterialComponents.Light

정의에 따르면 테마 오버레이는 여러 가지를 지정하지 않으며, 개별적으로 사용해서는 안 됩니다. 예를들어 Activity의 Theme로 사용해서는 안된다. 

 

실제로 앱에서 사용할 수 있는 2가지 "유형" 테마를 생각할 수 있습니다.

 

1. "전체" 테마.

화면에 필요한 모든 것을 지정합니다. Theme.MaterialComponents와 같은 또 다른 "전체" 테마에서 상속되며 Activity을 테마로 지정하는 데 사용해야 합니다.

 

2. 오버레이 테마 

전체 테마에 오버레이 적용되도록 의도되었습니다. 즉, 중요하고 필요한 사항을 지정하지 않을 가능성이 있으므로 단독으로 사용해서는 안 됩니다.

 

Ever-present

앱에서 테마를 지정하지 않더라도 항상 기본 테마가 적용됩니다.

위의 예는 단순화한 것이므로 View 내에서 전체 테마를 사용해서는 안 되며 대신 테마 오버레이를 사용하면 됩니다.

 

<!-- Copyright 2019 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 -->
<ViewGroup …
-   android:theme="@style/Theme.App.Foo">
+   android:theme="@style/ThemeOverlay.App.Foo">
<Button …
-   android:theme="@style/Theme.App.Bar"/>
+   android:theme="@style/ThemeOverlay.App.Bar"/>
</ViewGroup>

이러한 오버레이는 단독으로 사용하지는 않지만 둘러싸는 Activity의 Theme에 오버레이되어 사용됩니다.

 

Cost : Benefit

테마 사용에는 runTIme Cost가 들어갑니다. 

android:theme를 선언할 때마다 새로운 Theme 및 Resources 인스턴스를 할당하는 새로운 ContextThemeWrapper를 생성합니다. 또한 스타일링 간접 참조 수준을 더 많이 필요로 한다.

 

특히 RecyclerView item의 레이아웃이나 프로필의 영향을 모니터링하기 위해 반복되는 상황에서 테마를 너무 자유롭게 사용하지 않도록 주의하십시오

Use in Context

우리는 Theme가 Context와 연관되어 있다고 말했습니다.

즉, Context를 사용하여 코드에서 리소스를 검색하는 경우 올바른 컨텍스트를 사용하도록 주의해야 합니다.

예를 들어 코드의 어딘가에서 Drawable을 검색할 수 있습니다.

 

someView.background = AppCompatResources.getDrawable(requireContext(), R.drawable.foo)

 

drawable이 테마 속성을 참조하는 경우(모든 드로어블은 API 21 이상에서 수행할 수 있고 VectorDrawable은 Jetpack을 통해 API 14 이상에서 수행할 수 있음) 올바른 컨텍스트를 사용하여 drawable을 로드하는지 확인해야 합니다.

 

그렇지 않으면 하위 계층에 테마를 적용하려고 할 때, drawable이 왜 테마 속성을 반영하지 않는지 궁금해 할 때 좌절할 수 있습니다.

 

예를 들어 Fragment 또는 Activity의 Context를 사용하여 drawable을 로드하는 경우 트리 아래쪽에 적용된 테마를 고려하지 않습니다. 대신 Resource가 사용될 위치에 가장 가까운 Context를 사용하십시오.

 

someView.background = AppCompatResources.getDrawable(someView.context, R.drawable.foo)

Mis-Application

Activity > ViewGroup > View 등 Tree 에 존재하는 테마와 컨텍스트에 대해 이야기했습니다.

매니페스트의 <application> 태그에 테마를 지정할 수 있으므로 Application 클래스를 포함하도록 위의 트리를 확장하고 싶을 수 있습니다. Application > Activity > ViewGroup > View  이에 속지마세요!!

 

Application context는 테마 정보를 유지하지 않으며, 매니페스트에서 설정할 수 있는 테마는 테마를 명시적으로 설정하지 않은 Activity에 대한 대체 수단으로만 사용됩니다.

따라서 Application context를 사용하여 테마(예: 드로어블 또는 색상)에 따라 다를 수 있는 리소스를 로드하거나 테마 속성을 해결해서는 안 됩니다

 

애플리케이션 컨텍스트를 사용하여 테마에 사용할 리소스를 로드하지 마십시오.

Activity에 "전체" 테마를 지정하고 모든 애플리케이션 전체 테마에서 확장하도록 구성하는 이유이다

Build up

 테마가 트리에서 조상을 오버레이하는 방법과 앱의 스타일을 지정할 때 이 동작이 어떻게 유용할 수 있는지 설명했습니다.

android:theme 태그를 사용하여 레이아웃의 테마 섹션에 사용하고, 테마 오버레이를 사용하여 필요한 속성만 조정하세요.

올바른 테마와 컨텍스트를 사용하여 리소스를 로드하고 애플리케이션 컨텍스트에 주의하십시오!