카드 시작하기


앱에서 카드를 제공하려면 앱의 build.gradle 파일에 다음 종속 항목을 포함합니다.

Groovy

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.6.2"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.4.2"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.4.2"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.4.2"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.6.2"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.6.2"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.6.2")

    // Use to utilize standard components and layouts in your tiles
    implementation("androidx.wear.protolayout:protolayout:1.4.2")

    // Use to utilize components and layouts with Material Design in your tiles
    implementation("androidx.wear.protolayout:protolayout-material:1.4.2")

    // Use to include dynamic expressions in your tiles
    implementation("androidx.wear.protolayout:protolayout-expression:1.4.2")

    // Use to preview wear tiles in your own app
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.6.2")

    // Use to fetch tiles from a tile provider in your tests
    testImplementation("androidx.wear.tiles:tiles-testing:1.6.2")
}

주요 개념

카드는 Android 앱과 동일한 방식으로 빌드되지 않으며 다른 개념을 사용합니다.

  • 레이아웃 템플릿: 디스플레이에서 시각적 요소의 전체적인 배치를 정의합니다. 이 작업은 primaryLayout() 함수를 통해 실행됩니다.
  • 레이아웃 요소: 버튼 또는 카드와 같은 개별 그래픽 요소 또는 열, buttonGroup 등을 사용하여 그룹화된 여러 요소를 나타냅니다. 이러한 요소는 레이아웃 템플릿 내에 삽입됩니다.
  • 리소스: ResourceBuilders.Resources 객체는 레이아웃을 렌더링하는 데 필요한 Android 리소스(이미지)의 키-값 쌍 맵과 버전으로 구성됩니다.
  • 타임라인: TimelineBuilders.Timeline 객체는 레이아웃 객체의 인스턴스 하나 이상으로 구성된 목록입니다. 렌더러가 한 레이아웃 객체에서 다른 레이아웃 객체로 전환해야 하는 시점을 나타내는 다양한 메커니즘과 표현식을 제공할 수 있습니다(예: 특정 시간에 레이아웃 표시 중지).
  • 상태: 두 구성요소가 서로 통신할 수 있도록 카드와 앱 간에 전달되는 StateBuilders.State 유형의 데이터 구조입니다. 예를 들어 카드의 버튼을 탭하면 상태에 버튼 ID가 포함됩니다. 지도를 사용하여 데이터 유형을 교환할 수도 있습니다.
  • 카드: 카드를 나타내는 TileBuilders.Tile 객체로, 타임라인, 리소스 버전 ID, 최신 상태 간격, 상태로 구성됩니다.
  • Protolayout: 이 용어는 다양한 카드 관련 클래스의 이름에 표시되며 다양한 Wear OS 표시 경로에서 사용되는 그래픽 라이브러리인 Wear OS Protolayout 라이브러리를 나타냅니다.

카드 만들기

Material3TileService 사용(권장)

Material 3 타일(androidx.wear.tiles:tiles:1.6.0 이상)을 빌드할 때는 항상 하위 수준 TileService 클래스 대신 Material3TileService를 확장합니다. Material3TileService는 타일 개발을 간소화하는 독창적인 Kotlin 우선 아키텍처를 제공합니다.

  • 기본 제공 Kotlin 코루틴: ListenableFuture를 사용하고 onTileRequest()를 재정의하는 대신 단일 정지 MaterialScope.tileResponse(requestParams: TileRequest): Tile 함수를 구현합니다.
  • 사전 구성된 MaterialScope: tileResponse()는 MaterialScope를 수신자로 사용하여 실행되므로(allowDynamicTheme 및 defaultColorScheme와 같은 생성자 매개변수를 통해 구성됨) 중복된 materialScope() 호출로 레이아웃을 래핑할 필요가 없습니다.
  • 단일 호출 리소스 등록: 인라인 이미지 리소스를 자동으로 등록하고 단일 시스템 바인더 호출에서 타일 레이아웃과 리소스를 모두 반환하는 ProtoLayoutScope를 포함합니다. Material3TileService는 리소스를 자동으로 처리하므로(final onTileResourcesRequest()) onTileResourcesRequest()를 재정의하지 마세요.
class MyTileService : Material3TileService() {

    override suspend fun MaterialScope.tileResponse(requestParams: TileRequest): Tile =
        tile(
            timeline =
            Timeline.fromLayoutElement(
                primaryLayout(
                    mainSlot = {
                        text("Hello, World!".layoutString, typography = BODY_LARGE)
                    }
                )
            )
        )
}

기본 TileService 아키텍처

Material3TileService는 기본 TileService 클래스를 기반으로 빌드되며, 이 가이드의 나머지 예시에서는 이 클래스를 사용하여 하위 수준 개념을 설명합니다.

앱에서 카드를 제공하려면 TileService 유형의 서비스를 구현하고 매니페스트에 등록합니다. 이를 통해 시스템은 onTileRequest() 호출 중에 필요한 타일을 요청하고 onTileResourcesRequest() 호출 중에 리소스를 요청합니다.

class MyTileService : TileService() {

    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setTileTimeline(
                    Timeline.fromLayoutElement(
                        materialScope(this, requestParams.deviceConfiguration) {
                            primaryLayout(
                                mainSlot = {
                                    text("Hello, World!".layoutString, typography = BODY_LARGE)
                                }
                            )
                        }
                    )
                )
                .build()
        )

    override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
        Futures.immediateFuture(Resources.Builder().setVersion(RESOURCES_VERSION).build())
}

다음으로, AndroidManifest.xml 파일의 <application> 태그 내부에 서비스를 추가합니다.

<service
    android:name=".snippets.m3.tile.MyTileService"
    android:label="@string/tile_label"
    android:description="@string/tile_description"
    android:icon="@mipmap/ic_launcher"
    android:exported="true"
    android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
    <intent-filter>
        <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
    </intent-filter>

    <meta-data android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_preview" />
</service>

권한과 인텐트 필터가 이 서비스를 카드 제공자로 등록합니다.

아이콘, 라벨, 설명, 미리보기 리소스는 사용자가 휴대전화나 시계에서 카드를 구성할 때 표시됩니다. 미리보기 리소스는 Android의 모든 표준 리소스 한정자를 지원하므로 화면 크기 및 기기 언어와 같은 요소에 따라 미리보기를 변경할 수 있습니다. 추가 권장사항은 미리보기 체크리스트를 참고하세요.

앱을 배포하고 카드를 카드 캐러셀에 추가합니다(카드를 미리 볼 수 있는 더 개발자 친화적인 방법도 있지만 지금은 수동으로 진행).

Material 3로 만든 Wear OS 카드에 'Hello World'라는 텍스트가 표시되어 있습니다.
그림 1. 'Hello World' 타일

전체 예시는 GitHub의 코드 샘플 또는 Codelab을 참고하세요.

카드 UI 만들기

Material 3 Expressive UI 요소는 Kotlin의 유형 안전 빌더 패턴을 기반으로 하는 구조화된 접근 방식을 사용하여 생성됩니다.

레이아웃

효과적이고 반응성이 뛰어난 카드 레이아웃을 만드는 데 필요한 디자인 원칙에 관한 안내는 카드의 일반적인 레이아웃을 참고하세요.

레이아웃을 만들려면 다음 단계를 따르세요.

  1. Material Design 범위 시작: materialScope() 함수를 호출하여 필요한 context 및 deviceConfiguration를 제공합니다. allowDynamicTheme 및 defaultColorScheme와 같은 선택적 매개변수를 포함할 수 있습니다. allowDynamicTheme는 기본적으로 true이고 defaultColorScheme는 동적 색상을 사용할 수 없을 때(예: 사용자가 기능을 사용 중지한 경우) 또는 기기에서 지원되지 않거나 allowDynamicTheme가 false인 경우에 사용되는 ColorScheme를 나타냅니다. 맞춤 TileService에서 backgroundImage()와 같은 ImageResource API를 사용하는 경우 대신 materialScopeWithResources()를 호출합니다.

  2. 범위 내에서 UI 빌드: 지정된 타일 레이아웃의 모든 UI 구성요소는 단일 최상위 materialScope() 호출의 람다 내에서 정의해야 합니다. primaryLayout() 및 textEdgeButton()와 같은 이러한 구성요소 함수는 MaterialScope의 확장 함수이며 이 수신기 범위에서 호출될 때만 사용할 수 있습니다.

    materialScope(
        context = context,
        deviceConfiguration =
        requestParams.deviceConfiguration, // requestParams is passed to onTileRequest
        defaultColorScheme = myFallbackColorScheme
    ) {
        // inside the MaterialScope, you can call functions like primaryLayout()
        primaryLayout(
            titleSlot = { text(text = "Title".layoutString) },
            mainSlot = { text(text = "Main Content".layoutString) },
            bottomSlot = {
                textEdgeButton(
                    labelContent = { text("Action".layoutString) },
                    onClick = clickable()
                )
            }
        )
    }

슬롯

M3에서 카드 레이아웃은 Compose에서 영감을 받은 접근 방식을 사용하여 세 가지 고유한 슬롯을 사용합니다. 위에서 아래로 다음과 같습니다.

  1. titleSlot: 일반적으로 기본 제목 또는 헤더에 사용됩니다.
  2. 핵심 콘텐츠의 mainSlot
  3. bottomSlot: 작업 또는 보조 정보에 자주 사용됩니다. 여기에는 에지 버튼도 표시됩니다.
titleSlot, mainSlot, bottomSlot을 보여주는 카드 레이아웃
그림 2. titleSlot, mainSlot, bottomSlot

각 슬롯의 콘텐츠는 다음과 같습니다.

  • titleSlot(선택사항): 일반적으로 text()에서 생성된 몇 단어입니다.
  • mainSlot(필수): 행, 열, 버튼 그룹과 같은 구조로 구성된 구성요소입니다. 이러한 구성요소는 서로 내부에 재귀적으로 삽입될 수도 있습니다. 예를 들어 열에 행이 포함될 수 있습니다.
  • bottomSlot(선택사항): 일반적으로 가장자리 밀착 버튼 또는 텍스트 라벨로 채워집니다.

카드는 스크롤할 수 없으므로 페이징, 스크롤 또는 긴 콘텐츠 목록 처리를 위한 구성요소가 없습니다. 글꼴 크기가 커지거나 번역으로 인해 텍스트가 길어지더라도 콘텐츠가 계속 표시되도록 주의하세요.

UI 구성요소

protolayout-material3 라이브러리는 Material 3 Expressive 사양 및 사용자 인터페이스 권장사항에 따라 설계된 다양한 구성요소를 제공합니다.

버튼

버튼은 주로 작업 지향적입니다. 특정 작업을 트리거하는 역할을 합니다. 아이콘이나 짧은 텍스트와 같은 각 버튼의 콘텐츠는 작업을 식별합니다.

  • textButton(): (짧은) 텍스트 콘텐츠를 위한 단일 슬롯이 있는 버튼
  • iconButton(): 아이콘을 나타내는 단일 슬롯이 있는 버튼
  • avatarButton(): 수직으로 쌓인 라벨과 보조 라벨을 나타내는 콘텐츠를 가져올 수 있는 최대 3개의 슬롯과 그 옆에 이미지(아바타)를 제공하는 알약 모양의 아바타 버튼
  • imageButton(): 추가 슬롯을 제공하지 않고 이미지만 제공하는 클릭 가능한 이미지 버튼(예: 배경으로 backgroundImage)
  • compactButton(): 아이콘과 그 옆에 있는 텍스트를 나타내는 가로로 쌓인 콘텐츠를 사용할 수 있는 슬롯을 최대 2개 제공하는 압축 버튼입니다.
  • button(): 수직으로 쌓인 라벨과 보조 라벨을 나타내는 콘텐츠와 그 옆에 있는 아이콘을 사용할 수 있는 최대 3개의 슬롯을 제공하는 알약 모양 버튼입니다.

에지 버튼

에지 버튼은 시계의 원형 화면 하단에 고정된 특수한 전체 너비 버튼으로, 현재 타일 화면에서 실행할 가장 중요한 작업을 나타냅니다.

  • iconEdgeButton(): 아이콘이나 이와 유사한 원형의 작은 콘텐츠를 사용할 수 있는 단일 슬롯을 제공하는 에지 버튼입니다.
  • textEdgeButton(): 텍스트 또는 이와 유사하게 길고 넓은 콘텐츠를 사용할 수 있는 단일 슬롯을 제공하는 에지 버튼입니다.

카드

카드는 주로 정보 중심입니다. 관련된 구조화된 데이터 모음을 표시합니다. 상호작용 카드를 만들 수 있지만 일반적으로 정보 요약이 표시되며, 사용자는 이를 탭하여 세부정보를 보거나 관련 작업을 실행할 수 있습니다.

  • titleCard(): 1~3개의 슬롯을 제공하는 타이틀 카드(일반적으로 텍스트 기반)
  • appCard(): 최대 5개의 슬롯을 제공하는 앱 카드(일반적으로 텍스트 기반)
  • textDataCard(): 세로로 쌓인 슬롯을 최대 3개까지 제공하는 데이터 카드입니다. 일반적으로 텍스트 또는 숫자 기반입니다.
  • iconDataCard(): 일반적으로 텍스트 또는 숫자 기반의 세로로 쌓인 슬롯을 최대 3개까지 제공하는 데이터 카드(아이콘 포함)
  • graphicDataCard(): 진행률 표시기와 같은 그래픽 데이터 슬롯과 최대 2개의 수직으로 쌓인 슬롯(일반적으로 텍스트 설명용)을 제공하는 그래픽 데이터 카드

진행 상태 표시기

그룹 레이아웃 요소

  • buttonGroup(): 하위 요소를 가로 순서로 배치하는 구성요소 레이아웃
  • primaryLayout(): 반응형이며 요소의 배치를 처리하는 추천 M3 레이아웃 스타일을 나타내는 전체 화면 레이아웃으로, 권장 여백과 패딩이 적용됩니다.

테마 적용

Material 3 Expressive에서 색상 시스템은 29개의 표준 색상 역할로 정의되며, 기본, 보조, 3차, 오류, 표면, 윤곽선의 6개 그룹으로 구성됩니다.

Material 3 Expressive 색상 시스템은 기본, 보조, 3차, 오류, 표면, 윤곽선과 같은 그룹으로 구성된 색상 역할을 보여줍니다.
그림 3. Material 3 Expressive 색상 시스템

ColorScheme는 이러한 29개 역할을 각각 해당 색상에 매핑하며, MaterialScope의 일부이고 구성요소가 그 안에서 생성되어야 하므로 구성표에서 자동으로 색상을 가져옵니다. 이 접근 방식을 사용하면 모든 UI 요소가 Material Design 표준을 자동으로 준수합니다.

사용자가 정의한 색 구성표(예: 브랜드 색상을 반영하는 색 구성표)와 시스템에서 제공하는 색 구성표(사용자의 현재 워치 페이스에서 파생된 색 구성표 또는 사용자가 선택한 색 구성표) 중에서 선택할 수 있도록 하려면 다음과 같이 MaterialScope를 초기화합니다.

val myColorScheme =
    ColorScheme(
        primary = Color.rgb(0, 0, 255).argb, // Blue
        onPrimary = Color.rgb(255, 255, 255).argb, // White
        // 27 more
    )

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    defaultColorScheme = myColorScheme
) {
    // If the user selects "no theme" in settings, myColorScheme is used.
    // Otherwise, the system-provided theme is used.
}

이 옵션을 선택하는 경우 테마에 관계없이 최적의 가시성을 위해 올바르게 색조를 지정할 수 있도록 흑백 카드 아이콘을 제공하세요.

제공하는 색 구성표로 타일이 표시되도록 하려면 allowDynamicTheme를 false로 설정하여 동적 테마 지원을 사용 중지합니다.

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    allowDynamicTheme = false,
    defaultColorScheme = myColorScheme
) {
    // myColorScheme is *always* used.
}

색상

각 개별 구성요소는 ColorScheme에서 정의한 29가지 색상 역할의 하위 집합을 사용합니다. 예를 들어 버튼은 최대 4가지 색상을 사용하며, 기본적으로 활성 ColorScheme의 '기본' 그룹에서 가져옵니다.

ButtonColors 구성요소 토큰 ColorScheme 역할
containerColor 기본
iconColor onPrimary
labelColor onPrimary
secondaryLabelColor onPrimary(불투명도 0.8)

Wear OS 디자인에 색상을 적용하는 방법에 관한 자세한 안내는 색상 디자인 가이드를 참고하세요.

특정 UI 요소의 기본 색상 토큰에서 벗어나야 할 수도 있습니다. 예를 들어 하나의 textEdgeButton가 '기본' 대신 '보조' 또는 '3차' 그룹의 색상을 사용하여 눈에 띄고 더 나은 대비를 제공하도록 할 수 있습니다.

여러 가지 방법으로 구성요소 색상을 맞춤설정할 수 있습니다.

  1. 사전 정의된 색상에 도우미 함수를 사용합니다. filledTonalButtonColors()와 같은 도우미 함수를 사용하여 Material 3 Expressive의 표준 버튼 스타일을 적용합니다. 이러한 함수는 MaterialScope 내의 활성 ColorScheme에서 적절한 역할에 채워진 스타일, 색조 스타일, 윤곽선 스타일과 같은 일반적인 스타일을 매핑하는 사전 구성된 ButtonColors 인스턴스를 만듭니다. 이렇게 하면 일반적인 버튼 유형에 대해 각 색상을 수동으로 정의하지 않고도 일관된 스타일을 적용할 수 있습니다.

    textEdgeButton(
        colors = filledButtonColors(), // default
        /* OR colors = filledTonalButtonColors() */
        /* OR colors = filledVariantButtonColors() */
        // ... other parameters
    )

    카드의 경우 이에 상응하는 filledCardColors() 함수 계열을 사용합니다.

    하나 또는 두 개의 토큰만 변경해야 하는 경우 copy() 메서드를 사용하여 도우미 함수에서 반환하는 ButtonColors 객체를 수정할 수도 있습니다.

    textEdgeButton(
        colors =
        filledButtonColors()
            .copy(
                containerColor = colorScheme.tertiary,
                labelColor = colorScheme.onTertiary
            ),
        // ... other parameters
    )

  2. 대체 색상 역할을 명시적으로 제공합니다. 자체 ButtonColors 객체를 만들어 구성요소에 전달합니다. 카드의 경우 이에 상응하는 CardColors 객체를 사용합니다.

    textEdgeButton(
        colors =
        ButtonColors(
            // the materialScope makes colorScheme available
            containerColor = colorScheme.secondary,
            iconColor = colorScheme.secondaryDim,
            labelColor = colorScheme.onSecondary,
            secondaryLabelColor = colorScheme.onSecondary
        ),
        // ... other parameters
    )

  3. 고정 색상을 지정합니다(주의해서 사용). 일반적으로 의미론적 역할(예: colorScheme.primary)에 따라 색상을 지정하는 것이 좋지만 직접 색상 값을 제공할 수도 있습니다. 이 접근 방식은 전체 테마와 불일치할 수 있으므로, 특히 테마가 동적으로 변경되는 경우에는 신중하게 사용해야 합니다.

    textEdgeButton(
        colors = filledButtonColors().copy(
            containerColor = android.graphics.Color.RED.argb, // Using named colors
            labelColor = 0xFFFFFF00.toInt().argb // Using a hex code for yellow
        ),
        // ... other parameters
    )

서체

디자인에서 서체를 효과적으로 사용하는 방법에 관한 자세한 내용은 서체 디자인 가이드를 참고하세요.

Wear OS 플랫폼 전반에서 시각적 일관성을 만들고 성능을 최적화하기 위해 카드의 모든 텍스트는 시스템 제공 글꼴을 사용하여 렌더링됩니다. 즉, 카드는 맞춤 서체를 지원하지 않습니다. Wear OS 6 이상에서는 OEM별 글꼴입니다. 대부분의 경우 가변 글꼴이므로 더 표현력이 풍부한 환경과 더 세밀한 제어를 제공합니다.

텍스트 스타일을 만들려면 일반적으로 서체 상수와 함께 text() 메서드를 사용합니다. 이 구성요소를 사용하면 Material 3 Expressive에서 사전 정의된 서체 역할을 활용할 수 있으므로 카드가 가독성과 계층 구조에 관한 확립된 서체 권장사항을 준수할 수 있습니다. 라이브러리는 BODY_MEDIUM와 같은 18개의 시맨틱 서체 상수 집합을 제공합니다. 이러한 상수는 크기 이외의 글꼴 축에도 영향을 미칩니다.

text(
    text = "Hello, World!".layoutString,
    typography = BODY_MEDIUM,
)

더 세밀하게 제어하려면 추가 설정을 제공하면 됩니다. Wear OS 6 이상에서는 가변 글꼴이 사용될 가능성이 높으며, italic, weight, width, roundness 축을 따라 수정할 수 있습니다. settings 매개변수를 사용하여 이러한 축을 제어할 수 있습니다.

text(
    text = "Hello, World".layoutString,
    italic = true,

    // Use elements defined in androidx.wear.protolayout.LayoutElementBuilders.FontSetting
    settings =
    listOf(
        weight(500),
        width(100F),
        roundness(100)
    ),
)

마지막으로 크기 또는 자간을 제어해야 하는 경우(권장하지 않음) text() 대신 basicText()를 사용하고 fontStyle()을 사용하여 fontStyle 속성의 값을 구성합니다.

모양 및 여백

shape 속성을 사용하여 거의 모든 구성요소의 모서리 반경을 변경할 수 있습니다. 값은 MaterialScope 속성 shapes에서 가져옵니다.

textButton(
    height = expand(),
    width = expand(),
    shape = shapes.medium, // OR another value like shapes.full
    colors = filledVariantButtonColors(),
    labelContent = { text("Hello, World!".layoutString) },
)

구성요소의 모양을 변경한 후 디스플레이 가장자리 주변에 공간이 너무 많거나 너무 적다고 생각되면 primaryLayout()의 margin 매개변수를 사용하여 여백을 조정합니다.

primaryLayout(
    mainSlot = {
        textButton(
            shape = shapes.small,
            /* ... */
        )
    },
    // margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins
    margins = MAX_PRIMARY_LAYOUT_MARGIN,
)

호

지원되는 Arc 컨테이너 하위 요소는 다음과 같습니다.

  • ArcLine: 호를 따라 곡선을 렌더링합니다.
  • ArcText: 호 안에서 곡선 텍스트를 렌더링합니다.
  • ArcAdapter: 호에 접하는 지점에 그려진 호의 기본 레이아웃 요소를 렌더링합니다.

자세한 내용은 각 요소 유형에 관한 참고 문서를 확인하세요.

수정자

사용 가능한 모든 레이아웃 요소에는 선택적으로 수정자를 적용할 수 있습니다. 이러한 수정자의 용도는 다음과 같습니다.

  • 레이아웃의 시각적 모양을 변경합니다. 예를 들어, 레이아웃 요소에 배경, 테두리 또는 패딩을 추가합니다.
  • 레이아웃에 관한 메타데이터를 추가합니다. 예를 들어, 스크린 리더와 함께 사용할 수 있도록 시맨틱 수정자를 레이아웃 요소에 추가합니다.
  • 기능을 추가합니다. 예를 들어, 레이아웃 요소에 클릭 가능한 수정자를 추가하여 대화형 카드를 만듭니다. 자세한 내용은 카드와 상호작용을 참고하세요.

예를 들어, 다음 코드 샘플에서와 같이 Image의 기본 디자인과 메타데이터를 맞춤설정할 수 있습니다.

private fun myImage(): LayoutElement =
    Image.Builder()
        .setWidth(dp(24f))
        .setHeight(dp(24f))
        .setResourceId("image_id")
        .setModifiers(
            Modifiers.Builder()
                .setBackground(Background.Builder().setColor(argb(0xFFFF0000.toInt())).build())
                .setPadding(ModifiersBuilders.Padding.Builder().setStart(dp(12f)).build())
                .setSemantics(Semantics.Builder().setContentDescription("Image description").build())
                .build()
        )
        .build()

Spannable

Spannable은 텍스트와 유사한 요소를 배치하는 특별한 유형의 컨테이너입니다. 이 기능은 텍스트의 큰 블록에서 하나의 하위 문자열에만 다른 스타일을 적용하려고 할 때 유용합니다. 이러한 작업은 Text 요소로는 할 수 없습니다.

Spannable 컨테이너는 Span 하위 요소로 채워집니다. 다른 하위 요소 또는 중첩된 Spannable 인스턴스는 허용되지 않습니다.

Span 하위 요소에는 두 가지 유형이 있습니다.

  • SpanText: 텍스트를 특정 스타일로 렌더링합니다.
  • SpanImage: 이미지를 텍스트와 함께 인라인으로 렌더링합니다.

예를 들어, 다음 코드 샘플과 같이 'Hello world' 카드에서 'world'를 기울임꼴로 표시하고 단어 사이에 이미지를 삽입할 수 있습니다.

private fun mySpannable(): LayoutElement =
    LayoutElementBuilders.Spannable.Builder()
        .addSpan(SpanText.Builder().setText("Hello ").build())
        .addSpan(SpanImage.Builder().setWidth(dp(24f)).setHeight(dp(24f)).setResourceId("image_id").build())
        .addSpan(
            SpanText.Builder()
                .setText("world")
                .setFontStyle(FontStyle.Builder().setItalic(true).build())
                .build()
        )
        .build()

리소스 사용하기

카드에서는 앱의 어떤 리소스에도 액세스하지 못합니다. 이는 Android 이미지 ID를 Image 레이아웃 요소에 전달해 확인할 수 없다는 의미입니다. 대신 onTileResourcesRequest() 메서드를 재정의하고 리소스를 직접 제공하세요.

onTileResourcesRequest() 메서드 내에 이미지를 제공하는 방법에는 두 가지가 있습니다.

override fun onTileResourcesRequest(
    requestParams: ResourcesRequest
) = Futures.immediateFuture(
    Resources.Builder()
        .setVersion("1")
        .addIdToImageMapping(
            "image_from_resource",
            ResourceBuilders.ImageResource.Builder()
                .setAndroidResourceByResId(
                    ResourceBuilders.AndroidImageResourceByResId.Builder()
                        .setResourceId(R.drawable.ic_walk)
                        .build()
                ).build()
        )
        .addIdToImageMapping(
            "image_inline",
            ResourceBuilders.ImageResource.Builder()
                .setInlineResource(
                    ResourceBuilders.InlineImageResource.Builder()
                        .setData(imageAsByteArray)
                        .setWidthPx(48)
                        .setHeightPx(48)
                        .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
                        .build()
                ).build()
        ).build()
)

카드 미리보기 이미지 체크리스트

시스템은 새 카드를 추가하기 위해 카드 캐러셀 편집기에서 Android 앱 매니페스트에 참조된 카드 미리보기 이미지를 표시합니다. 이 편집기는 Wear OS 기기와 휴대전화의 시계 호환 앱에 모두 표시됩니다.

사용자가 이 미리보기 이미지를 최대한 활용할 수 있도록 타일에 관한 다음 세부정보를 확인하세요.

  • 최신 디자인을 반영합니다. 미리보기는 카드의 최신 디자인을 정확하게 나타내야 합니다.
  • 권장 크기를 사용합니다. 최상의 디스플레이 품질과 우수한 사용자 환경을 제공하려면 미리보기 이미지의 크기가 400px x 400px여야 합니다.
  • 정적 색상 테마를 사용합니다. 동적 색상 테마가 아닌 카드의 정적 색상 테마를 사용합니다.
  • 앱 아이콘 포함 앱 아이콘이 미리보기 이미지 상단에 표시되는지 확인합니다.
  • 로드됨/로그인됨 상태를 표시합니다. 미리보기는 완전히 작동하는 '로드됨' 또는 '로그인됨' 상태를 표시해야 하며, 비어 있거나 자리표시자 콘텐츠가 없어야 합니다.
  • 맞춤설정에 리소스 확인 규칙을 활용합니다(선택사항). Android의 리소스 확인 규칙을 사용하여 기기의 디스플레이 크기, 언어 또는 언어 설정과 일치하는 미리보기를 제공하는 것이 좋습니다. 이는 카드의 모양이 기기마다 다른 경우에 특히 유용합니다.