Glance로 UI 빌드

이 페이지에서는 크기를 처리하고 유연한 반응형 광고 소재를 제공하는 방법을 설명합니다. 기존 Glance 구성요소를 사용하여 Glance

Box, Column, Row 사용

Glance에는 세 가지 기본 컴포저블 레이아웃이 있습니다.

  • Box: 요소를 다른 요소 위에 배치합니다. 이는 RelativeLayout로 변환됩니다.

  • Column: 세로축에서 요소를 나란히 배치합니다. 번역합니다. 세로 방향의 LinearLayout로 설정합니다.

  • Row: 가로축에서 요소를 서로 뒤에 배치합니다. 번역합니다. 가로 방향의 LinearLayout로 변환합니다.

Glance는 Scaffold 객체를 지원합니다. Column, Row, 지정된 Scaffold 객체 내의 Box 컴포저블

열, 행, 상자 레이아웃 이미지
그림 1. 열, 행, 상자가 있는 레이아웃의 예
를 통해 개인정보처리방침을 정의할 수 있습니다.

이러한 각 컴포저블을 사용하면 세로 및 가로 정렬을 정의할 수 있습니다. 너비, 높이, 두께 또는 패딩 제약 조건을 사용하여 특수키를 사용합니다. 또한 각 하위 요소는 수정자를 정의하여 공백을 변경할 수 있습니다. 배치를 확인할 수 있습니다.

다음 예는 Row를 만드는 방법을 보여줍니다. 다음 그림 1과 같이 하위 요소를 수평으로 배열합니다.

Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) {
    val modifier = GlanceModifier.defaultWeight()
    Text("first", modifier)
    Text("second", modifier)
    Text("third", modifier)
}

Row는 사용 가능한 최대 너비를 채우며, 각 하위 요소가 동일하기 때문에 사용 가능한 공간을 균등하게 공유합니다. 서로 다른 가중치를 정의할 수 있고, 크기, 패딩 또는 정렬을 사용하여 필요에 맞게 레이아웃을 조정할 수 있습니다.

스크롤 가능한 레이아웃 사용

반응형 콘텐츠를 제공하는 또 다른 방법은 스크롤 가능하게 만드는 것입니다. 이것은 LazyColumn 컴포저블을 사용하면 됩니다. 이 컴포저블을 사용하면 앱 위젯의 스크롤 가능한 컨테이너 내에 표시할 항목의 개수입니다.

다음 스니펫은 LazyColumn

다음과 같은 항목의 수를 제공할 수 있습니다.

// Remember to import Glance Composables
// import androidx.glance.appwidget.layout.LazyColumn

LazyColumn {
    items(10) { index: Int ->
        Text(
            text = "Item $index",
            modifier = GlanceModifier.fillMaxWidth()
        )
    }
}

개별 항목 제공:

LazyColumn {
    item {
        Text("First Item")
    }
    item {
        Text("Second Item")
    }
}

항목 목록 또는 배열을 제공합니다.

LazyColumn {
    items(peopleNameList) { name ->
        Text(name)
    }
}

앞의 예를 조합하여 사용할 수도 있습니다.

LazyColumn {
    item {
        Text("Names:")
    }
    items(peopleNameList) { name ->
        Text(name)
    }

    // or in case you need the index:
    itemsIndexed(peopleNameList) { index, person ->
        Text("$person at index $index")
    }
}

이전 스니펫은 itemId를 지정하지 않습니다. 이 itemId는 성능을 개선하고 스크롤을 유지하는 데 도움이 됩니다. Android 12부터 목록 및 appWidget 업데이트를 통해 포지셔닝합니다( (예: 목록에서 항목을 추가하거나 삭제하는 경우)). 다음 예를 참고하세요. itemId 지정 방법을 보여줍니다.

items(items = peopleList, key = { person -> person.id }) { person ->
    Text(person.name)
}

SizeMode 정의

AppWidget 크기는 기기, 사용자 선택 또는 런처에 따라 다를 수 있습니다. 따라서 유연한 위젯 레이아웃 페이지를 참조하세요. Glance는 SizeMode를 통해 이를 단순화합니다. 정의 및 LocalSize 값 다음 섹션에서는 이 세 가지 방법을 설명합니다. 있습니다.

SizeMode.Single

SizeMode.Single가 기본 모드입니다. 이는 다음 중 한 가지 유형만 제공되는지 확인합니다. 즉, 사용 가능한 AppWidget 크기가 변경되더라도 콘텐츠 크기는 변경되지 않습니다.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Single

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the minimum size or resizable
        // size defined in the App Widget metadata
        val size = LocalSize.current
        // ...
    }
}

이 모드를 사용할 때는 다음을 확인하세요.

  • 최소 및 최대 크기 메타데이터 값은 콘텐츠 크기와 관련이 있습니다.
  • 콘텐츠가 예상 크기 범위 내에서 충분히 유연합니다.

일반적으로 다음과 같은 경우 이 모드를 사용해야 합니다.

a) AppWidget의 크기가 고정되어 있거나, b) 크기를 조절해도 콘텐츠가 변경되지 않습니다.

SizeMode.Responsive

이 모드는 반응형 레이아웃을 제공하는 것과 같으며, 이를 통해 GlanceAppWidget: 특정 있습니다. 정의된 각 크기에 대해 콘텐츠가 생성되어 특정 AppWidget가 생성되거나 업데이트될 때의 크기를 반환합니다. 그러면 시스템에서 가장 잘 맞는 크기를 선택합니다.

예를 들어 대상 AppWidget에서 세 가지 크기와 콘텐츠:

class MyAppWidget : GlanceAppWidget() {

    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

    override val sizeMode = SizeMode.Responsive(
        setOf(
            SMALL_SQUARE,
            HORIZONTAL_RECTANGLE,
            BIG_SQUARE
        )
    )

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be one of the sizes defined above.
        val size = LocalSize.current
        Column {
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            }
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width >= HORIZONTAL_RECTANGLE.width) {
                    Button("School")
                }
            }
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "provided by X")
            }
        }
    }
}

이전 예에서 provideContent 메서드는 세 번 호출되며 정의된 크기에 매핑됩니다.

  • 첫 번째 호출에서 크기는 100x100로 평가됩니다. 콘텐츠가 추가 버튼이나 상단 및 하단 텍스트를 포함하지 마세요.
  • 두 번째 호출에서 크기는 250x100로 평가됩니다. 콘텐츠에는 추가 버튼을 사용하고 상단과 하단 텍스트는 사용하지 않습니다.
  • 세 번째 호출에서 크기는 250x250로 평가됩니다. 콘텐츠에는 추가 버튼과 두 텍스트를 모두 사용합니다.

SizeMode.Responsive는 다른 두 모드의 조합으로, 이 모드를 사용하면 미리 정의된 경계 내에서 반응형 콘텐츠를 정의합니다. 일반적으로 이 모드는 성능이 향상되고 AppWidget의 크기가 조절될 때 전환이 더 원활해집니다.

다음 표는 SizeMode 및 사용 가능한 AppWidget 크기:

사용 가능한 크기 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Single 110 x 110 110 x 110 110 x 110 110 x 110
SizeMode.Exact 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Responsive 80 x 100 80 x 100 80 x 100 150 x 120
* 정확한 값은 데모용입니다.

SizeMode.Exact

SizeMode.Exact정확한 레이아웃을 제공하는 것과 같습니다. 사용 가능한 AppWidget 크기가 있을 때마다 GlanceAppWidget 콘텐츠를 요청합니다. (예: 사용자가 홈 화면에서 AppWidget의 크기를 조절하는 경우)

예를 들어 대상 위젯에서 지정할 수 있습니다.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Exact

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the size of the AppWidget
        val size = LocalSize.current
        Column {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width > 250.dp) {
                    Button("School")
                }
            }
        }
    }
}

이 모드는 다른 모드보다 더 많은 유연성을 제공하지만 몇 가지 기능이 제공됩니다. 주의사항:

  • AppWidget는 크기가 변경될 때마다 완전히 다시 만들어야 합니다. 이 콘텐츠가 복잡하면 성능 문제와 UI 점프가 발생할 수 있습니다.
  • 사용 가능한 크기는 런처의 구현에 따라 다를 수 있습니다. 예를 들어 런처가 크기 목록을 제공하지 않는 경우 크기가 사용됩니다.
  • Android 12 이전 기기에서는 크기 계산 로직이 일부 작동하지 않을 수 있습니다. 있습니다.

일반적으로 SizeMode.Responsive를 사용할 수 없는 경우 이 모드를 사용해야 합니다. 즉, 적은 수의 반응형 레이아웃은 실행할 수 없습니다.

리소스 액세스

LocalContext.current를 사용하여 모든 Android 리소스에 액세스합니다. 다음 예를 참고하세요.

LocalContext.current.getString(R.string.glance_title)

리소스 ID를 직접 제공하여 최종 RemoteViews 객체를 사용하고 동적 리소스(예: 동적)를 사용 설정합니다. 색상을 사용합니다.

컴포저블과 메서드는 다음과 같은 '제공자'를 사용하여 리소스를 허용합니다. ImageProvider 또는 다음과 같은 오버로드 메서드를 사용하여 GlanceModifier.background(R.color.blue)입니다. 예를 들면 다음과 같습니다.

Column(
    modifier = GlanceModifier.background(R.color.default_widget_background)
) { /**...*/ }

Image(
    provider = ImageProvider(R.drawable.ic_logo),
    contentDescription = "My image",
)

텍스트 처리

Glance 1.1.0에는 텍스트 스타일을 설정하는 API가 포함되어 있습니다. 다음을 사용하여 텍스트 스타일 설정: TextStyle 클래스의 fontSize, fontWeight 또는 fontFamily 속성입니다.

fontFamily는 다음 예와 같이 모든 시스템 글꼴을 지원하지만 앱의 맞춤 글꼴은 지원되지 않습니다.

Text(
    style = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 18.sp,
        fontFamily = FontFamily.Monospace
    ),
    text = "Example Text"
)

복합 버튼 추가

복합 버튼은 Android 12에서 도입되었습니다. Glance는 역방향을 지원합니다 다음 복합 버튼 유형의 호환성:

이러한 복합 버튼은 각각 '선택됨' 있습니다.

var isApplesChecked by remember { mutableStateOf(false) }
var isEnabledSwitched by remember { mutableStateOf(false) }
var isRadioChecked by remember { mutableStateOf(0) }

CheckBox(
    checked = isApplesChecked,
    onCheckedChange = { isApplesChecked = !isApplesChecked },
    text = "Apples"
)

Switch(
    checked = isEnabledSwitched,
    onCheckedChange = { isEnabledSwitched = !isEnabledSwitched },
    text = "Enabled"
)

RadioButton(
    checked = isRadioChecked == 1,
    onClick = { isRadioChecked = 1 },
    text = "Checked"
)

상태가 변경되면 제공된 람다가 트리거됩니다. 사용자는 상태를 확인합니다.

class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        val myRepository = MyRepository.getInstance()

        provideContent {
            val scope = rememberCoroutineScope()

            val saveApple: (Boolean) -> Unit =
                { scope.launch { myRepository.saveApple(it) } }
            MyContent(saveApple)
        }
    }

    @Composable
    private fun MyContent(saveApple: (Boolean) -> Unit) {

        var isAppleChecked by remember { mutableStateOf(false) }

        Button(
            text = "Save",
            onClick = { saveApple(isAppleChecked) }
        )
    }
}

colors 속성을 CheckBox, Switch, RadioButton를 사용하여 색상을 맞춤설정합니다.

CheckBox(
    // ...
    colors = CheckboxDefaults.colors(
        checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight),
        uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked }
)

Switch(
    // ...
    colors = SwitchDefaults.colors(
        checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan),
        uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta),
        checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow),
        uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked },
    text = "Enabled"
)

RadioButton(
    // ...
    colors = RadioButtonDefaults.colors(
        checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow),
        uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue)
    ),

)

추가 구성요소

Glance 1.1.0에는 다음 표를 참조하세요.

이름 이미지 참조 링크 추가 참고사항
채워진 버튼 alt_text 구성요소
윤곽선 버튼 alt_text 구성요소
아이콘 버튼 alt_text 구성요소 기본 / 보조 / 아이콘만
제목 표시줄 alt_text 구성요소
Scaffold Scaffold와 제목 표시줄이 같은 데모에 있습니다.

디자인 세부사항에 대한 자세한 내용은 이 도움말의 구성요소 디자인을 참조하세요. 디자인 키트를 사용해 보세요.