반응형
- 위젯을 구현하다 보면 사이즈 별로 다른 레이아웃을 제공하거나 높이 너비에 따라 View의 구성이 달라지는 구현을 필요로 할 때가 있다.
- 기존 RemoteViews에서는 AppWidgetInfo에 접근하여 사이즈 값에 대해 확인했으나 Glance에서는 좀 다르다.
appWidgetManager.getAppWidgetInfo(appWidgetId).minHeight
- SizeMode 라는 값을 통해 위젯 크기 변화에 따른 레이아웃 구성 대응이 가능하다.
- SizeMode는 Glance 위젯이 시스템에서 요구하는 사이즈 정보의 유연성을 어떻게 처리할지를 정의한다.
sealed interface SizeMode {
/**
* The [GlanceAppWidget] provides a single UI.
*
* The [LocalSize] will be the minimum size the App Widget can be, as defined in
* the App Widget provider info (see [android.appwidget.AppWidgetManager.getAppWidgetInfo]).
*/
object Single : SizeMode {
override fun toString(): String = "SizeMode.Single"
}
/**
* The [GlanceAppWidget] provides a UI for each size the App Widget may be displayed at. The
* list of sizes is provided by the options bundle (see
* [android.appwidget.AppWidgetManager.getAppWidgetOptions]).
*
* The composable will be called for each size. During that call, the [LocalSize] will be the
* one for which the UI is generated.
*/
object Exact : SizeMode {
override fun toString(): String = "SizeMode.Exact"
}
/**
* The [GlanceAppWidget] provides a UI for a fixed set of sizes.
*
* On Android 12 and later, the composable will be called once per size provided and the
* mapping from size to view will be sent to the system. The framework will then decide which
* view to display based on the current size of the App Widget (see
* [android.widget.RemoteViews] for details)
*
* Before Android 12, the composable will be called for each size at which the app widget may be
* displayed (like for [Exact]). For each size, the best view will be chosen, which is the
* largest one that fits in the available space, or the smallest one if none fit.
*
* @param sizes List of sizes to use, must not be empty.
*/
class Responsive(val sizes: Set<DpSize>) : SizeMode {
init {
require(sizes.isNotEmpty()) { "The set of sizes cannot be empty" }
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Responsive
if (sizes != other.sizes) return false
return true
}
override fun hashCode(): Int = sizes.hashCode()
override fun toString(): String = "SizeMode.Responsive(sizes=$sizes)"
}
}
SizeMode.Exact
- provideGlance() 호출 시 지정된 크기에만 맞춰 레이아웃이 그려짐
- 사용자가 위젯을 여러 사이즈로 조절하더라도 고정된 레이아웃만 사용한다.
- 높이에 따라 특정 뷰를 처리하는 데에 용이하다. 예를 들어 리스트가 들어간 위젯인데, 현재 위젯 높이에서 리스트를 다 보여주지 못하면 보이지 않는 개수만큼 +x 표시를 한다던지..
val enableListHeight = LocalSize.current.height.value.toInt().dp - fixedHeight
val maxHolderCount = enableListHeight / holderHeight
val visibleList = blockList.take(maxHolderCount.toInt())
SizeMode.Single
- Exact와 유사하게 동작하지만, 내부적으로는 SizeMode.Responsive 기반으로 처리될 수 있음 (거의 같은 의미)
SizeMode.Responsive
- 여러 사이즈에 대응하는 레이아웃 제공 가능
- 시스템은 다양한 위젯 크기에 따라 provideGlance()를 여러 번 호출하며 각각 다른 Glance UI를 만들 수 있음
- provideContent() 안에서 LocalSize.current 값을 이용해 사이즈별로 UI 다르게 구성 가능
when {
LocalSize.current.width > 200.dp -> { /* 큰 위젯용 UI */ }
else -> { /* 작은 위젯용 UI */ }
}
- 이렇게 sizeMode를 지정해주고, 컴포저블에서 LocalSize로 접근할 수 있다.
class TodoListWidget : GlanceAppWidget() {
override val sizeMode = SizeMode.Exact
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
val enableListHeight = LocalSize.current.height
}
}
반응형