สร้างแอปที่สมบูรณ์ด้วย Relay และ Jetpack Compose

1. ก่อนเริ่มต้น

Relay เป็นชุดเครื่องมือที่ช่วยให้ทีมออกแบบคอมโพเนนต์ UI ใน Figma และใช้คอมโพเนนต์เหล่านั้นในโปรเจ็กต์ Jetpack Compose ได้โดยตรง ซึ่งจะช่วยลดความซับซ้อนของข้อกำหนดการออกแบบและวงจร QA ซึ่งช่วยให้ทีมส่ง UI ของ Android ที่ยอดเยี่ยมได้อย่างรวดเร็ว

ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีผสานรวมแพ็กเกจ UI ของ Relay เข้ากับกระบวนการพัฒนา Compose โดยมุ่งเน้นที่เทคนิคการผสานรวม ไม่ใช่เวิร์กโฟลว์ตั้งแต่ต้นจบ ดูข้อมูลเกี่ยวกับเวิร์กโฟลว์ทั่วไปของ Relay ได้ที่บทแนะนําเบื้องต้นเกี่ยวกับ Relay

ข้อกำหนดเบื้องต้น

  • ประสบการณ์พื้นฐานในการใช้ Compose หากยังไม่ได้ทำ ให้ทำตาม Codelab พื้นฐานของ Jetpack Compose
  • มีประสบการณ์เกี่ยวกับไวยากรณ์ Kotlin

สิ่งที่จะได้เรียนรู้

  • วิธีนําเข้าแพ็กเกจ UI
  • วิธีผสานรวมแพ็กเกจ UI กับการนําทางและสถาปัตยกรรมข้อมูล
  • วิธีรวมแพ็กเกจ UI ด้วยตรรกะตัวควบคุม
  • วิธีจับคู่สไตล์ Figma กับธีม Compose
  • วิธีแทนที่แพ็กเกจ UI ด้วยคอมโพสิเบิลที่มีอยู่ในโค้ดที่สร้างขึ้น

สิ่งที่คุณจะสร้าง

  • การออกแบบแอปที่เหมือนจริงโดยอิงตามแพ็กเกจ Relay ที่นักออกแบบให้มา แอปนี้มีชื่อว่า Reflect ซึ่งเป็นแอปติดตามรายวันที่ส่งเสริมสติและนิสัยที่ดี ซึ่งประกอบด้วยคอลเล็กชันเครื่องมือติดตามประเภทต่างๆ และ UI สำหรับเพิ่มและจัดการเครื่องมือติดตาม แอปมีลักษณะดังรูปภาพต่อไปนี้

แอปที่เสร็จสมบูรณ์

สิ่งที่ต้องมี

2. ตั้งค่า

รับรหัส

หากต้องการดูโค้ดสําหรับโค้ดแล็บนี้ ให้ทําอย่างใดอย่างหนึ่งต่อไปนี้

$ git clone https://github.com/googlecodelabs/relay-codelabs
  • ไปที่ที่เก็บ relay-codelabs ใน GitHub เลือกสาขาที่ต้องการ แล้วคลิกโค้ด > ดาวน์โหลด ZIP จากนั้นแตกไฟล์ ZIP ที่ดาวน์โหลดมา

ไม่ว่าในกรณีใดก็ตาม สาขา main จะมีโค้ดเริ่มต้นและสาขา end จะมีโค้ดโซลูชัน

ติดตั้งปลั๊กอิน Relay สำหรับ Android Studio

หากยังไม่มีปลั๊กอิน Relay สำหรับ Android Studio ให้ทำตามขั้นตอนต่อไปนี้

  1. ใน Android Studio ให้คลิกการตั้งค่า > ปลั๊กอิน
  2. ป้อน Relay for Android Studio ในกล่องข้อความ
  3. คลิกติดตั้งในส่วนขยายที่ปรากฏในผลการค้นหา

การตั้งค่าปลั๊กอิน Android Studio

  1. หากเห็นกล่องโต้ตอบหมายเหตุเกี่ยวกับความเป็นส่วนตัวของปลั๊กอินของบุคคลที่สาม ให้คลิกยอมรับ
  2. คลิก OK > Restart
  3. หากเห็นกล่องโต้ตอบยืนยันการออก ให้คลิกออก

เชื่อมต่อ Android Studio กับ Figma

Relay จะดึงข้อมูลแพ็กเกจ UI ด้วย Figma API หากต้องการใช้ฟีเจอร์นี้ คุณต้องมีบัญชี Figma ฟรีและโทเค็นการเข้าถึงส่วนบุคคล จึงจะอยู่ในส่วนสิ่งที่ต้องมี

หากยังไม่ได้เชื่อมต่อ Android Studio กับ Figma ให้ทำตามขั้นตอนต่อไปนี้

  1. ในบัญชี Figma ให้คลิกไอคอนโปรไฟล์ที่ด้านบนของหน้า แล้วเลือกการตั้งค่า
  2. ในส่วนโทเค็นการเข้าถึงส่วนบุคคล ให้ป้อนคำอธิบายโทเค็นในกล่องข้อความ แล้วกด Enter (หรือ return ใน macOS) ระบบจะสร้างโทเค็น
  3. คลิกคัดลอกโทเค็นนี้

โทเค็นการเข้าถึงที่สร้างใน Figma

  1. ใน Android Studio ให้เลือกเครื่องมือ > การตั้งค่ารีเลย์ กล่องโต้ตอบการตั้งค่ารีเลย์จะปรากฏขึ้น
  2. ในกล่องข้อความโทเค็นการเข้าถึง Figma ให้วางโทเค็นการเข้าถึง แล้วคลิก OK ตั้งค่าสภาพแวดล้อมแล้ว

3. ตรวจสอบการออกแบบของแอป

สำหรับแอป Reflect เราทำงานร่วมกับนักออกแบบเพื่อช่วยกำหนดสี การจัดวางตัวอักษร เลย์เอาต์ และลักษณะการทํางานของแอป เราออกแบบเหล่านี้ตามแบบแผนของ Material Design 3 เพื่อให้แอปทำงานร่วมกับคอมโพเนนต์และธีม Material ได้อย่างราบรื่น

ตรวจสอบหน้าจอหลัก

หน้าจอหลักจะแสดงรายการเครื่องมือติดตามที่ผู้ใช้กําหนด รวมถึงช่วยให้คุณเปลี่ยนวันที่มีการใช้งานและสร้างเครื่องมือติดตามอื่นๆ ได้ด้วย

หน้าจอหลัก

ใน Figma นักออกแบบของเราแบ่งหน้าจอนี้ออกเป็นคอมโพเนนต์หลายรายการ กำหนด API ของคอมโพเนนต์เหล่านั้น และแพ็กเกจไว้กับปลั๊กอิน Relay สำหรับ Figma หลังจากแพ็กเกจคอมโพเนนต์เหล่านี้แล้ว คุณจะนําเข้าคอมโพเนนต์เหล่านั้นไปยังโปรเจ็กต์ Android Studio ได้

คอมโพเนนต์หน้าจอหลัก

ตรวจสอบหน้าจอเพิ่ม/แก้ไข

หน้าจอเพิ่ม/แก้ไขช่วยให้ผู้ใช้เพิ่มหรือแก้ไขอุปกรณ์ติดตามได้ รูปแบบที่แสดงจะแตกต่างกันเล็กน้อยตามประเภทเครื่องมือติดตาม

หน้าจอเพิ่ม/แก้ไข

ในทํานองเดียวกัน หน้าจอนี้จะแบ่งออกเป็นคอมโพเนนต์ที่แพ็กเกจไว้หลายรายการ

เพิ่ม/แก้ไขคอมโพเนนต์หน้าจอ

ตรวจสอบธีม

สีและแบบอักษรของการออกแบบนี้ใช้รูปแบบ Figma ตามชื่อโทเค็นของ Material Design 3 ซึ่งจะช่วยให้ทำงานร่วมกันกับธีม Compose และ Material Components ได้ดียิ่งขึ้น

รูปแบบ Figma

4. นําเข้าแพ็กเกจ UI

คุณต้องอัปโหลดแหล่งที่มาของการออกแบบไปยัง Figma ก่อนจึงจะนําเข้าแพ็กเกจ UI ไปยังโปรเจ็กต์ได้

หากต้องการดูลิงก์ไปยังแหล่งที่มาของ Figma ให้ทำตามขั้นตอนต่อไปนี้

  1. ใน Figma ให้คลิกนําเข้าไฟล์ แล้วเลือกไฟล์ ReflectDesign.fig ที่พบในโฟลเดอร์โปรเจ็กต์ CompleteAppCodelab
  2. คลิกขวาที่ไฟล์ แล้วเลือกคัดลอกลิงก์ ซึ่งจะต้องใช้ในส่วนถัดไป

88afd168463bf7e5.png

นําเข้าแพ็กเกจ UI ไปยังโปรเจ็กต์

  1. เปิดโปรเจ็กต์ ./CompleteAppCodelab ใน Android Studio
  2. คลิก File > New > Import UI Packages กล่องโต้ตอบนําเข้าแพ็กเกจ UI จะปรากฏขึ้น
  3. วาง URL ที่คัดลอกไว้ในส่วนก่อนหน้าในกล่องข้อความ URL แหล่งที่มาของ Figma

f75d0c3e17b6f75.png

  1. ในกล่องข้อความธีมแอป ให้ป้อน com.google.relay.example.reflect.ui.theme.ReflectTheme วิธีนี้ช่วยให้มั่นใจว่าตัวอย่างเพลงที่สร้างขึ้นจะใช้ธีมที่กำหนดเอง
  2. คลิกถัดไป คุณจะเห็นตัวอย่างแพ็กเกจ UI ของไฟล์
  3. คลิกสร้าง ระบบจะนำเข้าแพ็กเกจไปยังโปรเจ็กต์
  4. ไปที่แท็บโปรเจ็กต์ แล้วคลิกลูกศรขยาย 2158ffa7379d2b2e.png ข้างโฟลเดอร์ ui-packages

โฟลเดอร์ ui-packages

  1. คลิก2158ffa7379d2b2e.pngลูกศรขยายข้างโฟลเดอร์แพ็กเกจ แล้วสังเกตว่ามีไฟล์ต้นฉบับ JSON และทรัพยากรที่เกี่ยวข้อง
  2. เปิดไฟล์ต้นฉบับ JSON โมดูล Relay จะแสดงตัวอย่างของแพ็กเกจและ API ของแพ็กเกจ

a6105146c4cfb47.png

สร้างและสร้างโค้ด

  1. ที่ด้านบนของ Android Studio ให้คลิก b3bc77f3c78cac1b.png สร้างโปรเจ็กต์ ระบบจะเพิ่มโค้ดที่สร้างขึ้นสำหรับแต่ละแพ็กเกจลงในโฟลเดอร์ java/com.google.relay.example.reflect คอมโพสิชันที่สร้างขึ้นจะมีข้อมูลเลย์เอาต์และการจัดรูปแบบทั้งหมดจากการออกแบบใน Figma
  2. เปิดไฟล์ com/google/relay/example/reflect/range/Range.kt
  3. โปรดทราบว่าระบบจะสร้างตัวอย่างการคอมโพสิทสำหรับคอมโพเนนต์แต่ละรูปแบบ หากจำเป็น ให้คลิกแยกเพื่อให้เห็นแผงรหัสและแผงแสดงตัวอย่างอยู่ข้างกัน

c0d21ab0622ad550.png

5. ผสานรวมคอมโพเนนต์

ในส่วนนี้ คุณจะเห็นรายละเอียดของโค้ดที่สร้างขึ้นสําหรับเครื่องมือติดตาม Switch

การออกแบบอุปกรณ์ติดตาม Switch

  1. เปิดไฟล์ com/google/relay/example/reflect/switch/Switch.kt ใน Android Studio

Switch.kt (สร้างขึ้น)

/**
 * This composable was generated from the UI Package 'switch'.
 * Generated code; don't edit directly.
 */
@Composable
fun Switch(
    modifier: Modifier = Modifier,
    isChecked: Boolean = false,
    emoji: String = "",
    title: String = ""
) {
    TopLevel(modifier = modifier) {
        if (isChecked) {
            ActiveOverlay(modifier = Modifier.rowWeight(1.0f).columnWeight(1.0f)) {}
        }
        TopLevelSynth(modifier = Modifier.rowWeight(1.0f)) {
            Label(modifier = Modifier.rowWeight(1.0f)) {
                Emoji(emoji = emoji)
                Title(
                    title = title,
                    modifier = Modifier.rowWeight(1.0f)
                )
            }
            Checkmark {
                if (isChecked) {
                    Icon()
                }
            }
        }
    }
}
  1. โปรดสังเกตสิ่งต่อไปนี้
  • ระบบจะสร้างเลย์เอาต์และการจัดสไตล์ทั้งหมดจากการออกแบบใน Figma
  • องค์ประกอบย่อยจะแบ่งออกเป็นคอมโพสิเบิลแยกกัน
  • ระบบจะสร้างตัวอย่างแบบคอมโพสได้สำหรับรูปแบบการออกแบบทั้งหมด
  • รูปแบบสีและแบบอักษรเป็นแบบฮาร์ดโค้ด คุณแก้ไขเรื่องนี้ในภายหลังได้

แทรกอุปกรณ์ติดตาม

  1. เปิดไฟล์ java/com/google/relay/example/reflect/ui/components/TrackerControl.kt ใน Android Studio ไฟล์นี้จะให้ข้อมูลและตรรกะการโต้ตอบแก่เครื่องมือติดตามพฤติกรรม
  2. สร้างและเรียกใช้แอปในโปรแกรมจำลอง ปัจจุบันคอมโพเนนต์นี้จะแสดงผลข้อมูลดิบจากรุ่นอุปกรณ์ติดตาม

5d56f8a7065066b7.png

  1. นําเข้าแพ็กเกจ com.google.relay.example.reflect.switch.Switch ไปยังไฟล์
  2. แทนที่ Text(text = trackerData.tracker.toString()) ด้วยบล็อก when ที่วางแนวในช่อง trackerData.tracker.type
  3. ในเนื้อหาของบล็อก when ให้เรียกใช้ฟังก์ชัน Switch() Composable เมื่อประเภทเป็น TrackerType.BOOLEAN

โค้ดของคุณควรมีลักษณะดังนี้

TrackerControl.kt

// TODO: replace with Relay tracker components
when (trackerData.tracker.type) {
    TrackerType.BOOLEAN ->
        Switch(
          title = trackerData.tracker.name,
          emoji = trackerData.tracker.emoji
        )
    else ->
        Text(trackerData.tracker.toString())
}
  1. สร้างโปรเจ็กต์อีกครั้ง ตอนนี้หน้าแรกแสดงผลเครื่องมือติดตาม Switch อย่างถูกต้องตามที่ออกแบบไว้ด้วยข้อมูลสด

4241e78b9f82075b.png

6. เพิ่มสถานะและการโต้ตอบ

แพ็กเกจ UI เป็นแบบไม่มีสถานะ สิ่งที่แสดงผลคือผลลัพธ์ง่ายๆ ของพารามิเตอร์ที่ส่งเข้ามา แต่แอปจริงต้องมีการโต้ตอบและสถานะ แฮนเดิลการโต้ตอบสามารถส่งไปยังคอมโพสิเบิลที่สร้างขึ้นได้เช่นเดียวกับพารามิเตอร์อื่นๆ แต่คุณจะเก็บสถานะที่ตัวแฮนเดิลเหล่านั้นจัดการไว้ที่ใด คุณจะหลีกเลี่ยงการส่งตัวแฮนเดิลเดียวกันไปยังอินสแตนซ์ทุกรายการได้อย่างไร คุณจะทำให้การคอมโพสแพ็กเกจเป็นคอมโพสิเบิลที่นำมาใช้ซ้ำได้ได้อย่างไร สำหรับกรณีเหล่านี้ เราขอแนะนำให้คุณรวมแพ็กเกจที่สร้างขึ้นไว้ในฟังก์ชัน Composable ที่กำหนดเอง

ตัดแพ็กเกจ UI ในฟังก์ชัน Composable ของตัวควบคุม

การรวมแพ็กเกจ UI ในฟังก์ชัน Composable ของตัวควบคุมช่วยให้คุณปรับแต่งการแสดงผลหรือตรรกะทางธุรกิจ และจัดการสถานะในเครื่องได้ (หากจำเป็น) นักออกแบบจะยังคงอัปเดตแพ็กเกจ UI เดิมใน Figma ได้โดยไม่ต้องอัปเดตโค้ด Wrapper

หากต้องการสร้างตัวควบคุมสำหรับอุปกรณ์ติดตาม Switch ให้ทำตามขั้นตอนต่อไปนี้

  1. เปิดไฟล์ java/com/google/relay/example/reflect/ui/components/SwitchControl.kt ใน Android Studio
  2. ในฟังก์ชัน SwitchControl() Composable ให้ส่งพารามิเตอร์ต่อไปนี้
  • trackerData: ออบเจ็กต์ TrackerData
  • modifier: ออบเจ็กต์ตัวตกแต่ง
  • onLongClick: การเรียกกลับการโต้ตอบเพื่อเปิดใช้การกดติดตามค้างไว้เพื่อแก้ไขและลบ
  1. แทรกฟังก์ชัน Switch() และส่งตัวแก้ไข combinedClickable เพื่อจัดการการคลิกและการกดค้าง
  2. ส่งค่าจากออบเจ็กต์ TrackerData ไปยังฟังก์ชัน Switch() รวมถึงเมธอด isToggled()

ฟังก์ชัน SwitchControl() ที่เสร็จสมบูรณ์จะมีลักษณะเป็นข้อมูลโค้ดต่อไปนี้

SwitchControl.kt

package com.google.relay.example.reflect.ui.components

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.relay.example.reflect.model.Tracker
import com.google.relay.example.reflect.model.TrackerData
import com.google.relay.example.reflect.model.TrackerType
import com.google.relay.example.reflect.switch.Switch

/*
 * A component for controlling switch-type trackers.
 *
 * SwitchControl is responsible for providing interaction and state management to the stateless
 * composable [Switch] generated by Relay. [onLongClick] provides a way for callers to supplement
 * the control's intrinsic interactions with, for example, a context menu.
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SwitchControl(
    trackerData: TrackerData,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
) {
    Switch(
        modifier
            .clip(shape = RoundedCornerShape(size = 32.dp))
            .combinedClickable(onLongClick = onLongClick) {
                trackerData.toggle()
            },
        emoji = trackerData.tracker.emoji,
        title = trackerData.tracker.name,
        isChecked = trackerData.isToggled(),
    )
}

@Preview
@Composable
fun SwitchControllerPreview() {
    val data = TrackerData(
        Tracker(
            emoji = "🍕",
            name = "Ate Pizza",
            type = TrackerType.BOOLEAN
        )
    )
    SwitchControl(data)
}
  1. ในไฟล์ TrackerControl.kt ให้นําการนําเข้า Switch ออก แล้วแทนที่ฟังก์ชัน Switch() ด้วยการเรียกใช้ฟังก์ชัน SwitchControl()
  2. เพิ่มกรณีสำหรับค่าคงที่ตัวระบุรายการ TrackerType.RANGE และ TrackerType.COUNT

บล็อก when ที่เสร็จสมบูรณ์จะมีลักษณะเป็นข้อมูลโค้ดต่อไปนี้

TrackerControl.kt

when (trackerData.tracker.type) {
    TrackerType.BOOLEAN ->
        SwitchControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
    TrackerType.RANGE ->
        RangeControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
    TrackerType.COUNT ->
        ValueControl(
            trackerData = trackerData,
            onLongClick = { expanded = true },
        )
}
  1. สร้างโปรเจ็กต์อีกครั้ง ตอนนี้คุณแสดงและโต้ตอบกับอุปกรณ์ติดตามได้แล้ว หน้าจอหลักเสร็จสมบูรณ์

b23b94f0034243d3.png

7. แมปคอมโพเนนต์ที่มีอยู่

Relay ช่วยให้นักพัฒนาซอฟต์แวร์ปรับแต่งโค้ดที่สร้างขึ้นได้โดยแทนที่แพ็กเกจ UI ด้วยคอมโพสิเบิลที่มีอยู่ วิธีนี้เป็นวิธีที่ยอดเยี่ยมในการแสดงผลคอมโพเนนต์ที่พร้อมใช้งานหรือแม้แต่ระบบการออกแบบที่กำหนดเองในโค้ด

แมปช่องข้อความ

รูปภาพต่อไปนี้เป็นการออกแบบคอมโพเนนต์ Tracker Settings ในกล่องโต้ตอบเพิ่ม/แก้ไขเครื่องมือติดตาม

การออกแบบสําหรับคอมโพเนนต์การตั้งค่าสวิตช์

นักออกแบบของเราใช้ ReflectTextField ในการออกแบบ ซึ่งเรามีการใช้งานในโค้ดที่สร้างขึ้นจากช่องข้อความ Material Design 3 อยู่แล้ว Figma ไม่รองรับช่องข้อความโดยกำเนิด ดังนั้นโค้ดเริ่มต้นที่ Relay สร้างขึ้นจึงมีหน้าตาเหมือนกับการออกแบบเท่านั้น ไม่ใช่การควบคุมที่ใช้งานได้

วิธีทดสอบการใช้งานปัจจุบันสําหรับ TrackerSettings

  1. ใน Android Studio ให้สร้างและเรียกใช้แอปในโปรแกรมจำลอง
  2. กดแถวอุปกรณ์ติดตามค้างไว้ แล้วเลือกแก้ไข
  3. แตะช่องข้อความ Title และสังเกตว่าช่องไม่ตอบสนองต่อการโต้ตอบ

หากต้องการแทนที่การติดตั้งใช้งานจริงสําหรับองค์ประกอบนี้ คุณต้องมี 2 อย่าง ได้แก่ แพ็กเกจ UI ของช่องข้อความและไฟล์การแมป แต่โชคดีที่นักออกแบบของเราได้แพ็กเกจคอมโพเนนต์ระบบการออกแบบใน Figma ไว้แล้วและใช้คอมโพเนนต์ช่องข้อความในการออกแบบสำหรับ Tracker Settings โดยค่าเริ่มต้น ระบบจะสร้างแพ็กเกจที่ฝังนี้ขึ้นเป็นข้อกำหนด แต่คุณใช้การแมปคอมโพเนนต์เพื่อเปลี่ยนแพ็กเกจได้

คอมโพเนนต์ Figma สำหรับช่องข้อความที่มีปลั๊กอิน Relay วางซ้อนกัน

สร้างไฟล์การแมป

ปลั๊กอิน Relay สำหรับ Android Studio มีทางลัดสำหรับสร้างไฟล์การแมปคอมโพเนนต์

หากต้องการสร้างไฟล์การแมป ให้ทําตามขั้นตอนต่อไปนี้

  1. ใน Android Studio ให้คลิกขวาที่แพ็กเกจ UI text_field แล้วเลือกสร้างไฟล์การแมป

สร้างรายการในเมนูตามบริบทของไฟล์การแมป

  1. กล่องโต้ตอบไฟล์การแมปจะปรากฏขึ้น ป้อนตัวเลือกต่อไปนี้
  • ในคอมโพสิเบิลเป้าหมาย ให้เลือกใช้คอมโพสิเบิลที่มีอยู่ แล้วป้อน com.google.relay.example.reflect.ui.components.ReflectTextField
  • ในไฟล์ที่สร้างขึ้น ให้เลือกสร้างการใช้งานและยกเลิกการเลือกสร้างตัวอย่างการคอมโพส

e776585c3b838b10.png

  1. คลิกสร้างไฟล์การแมป ซึ่งจะสร้างไฟล์การแมปต่อไปนี้

text_field.json

{
  "target": "ReflectTextField",
  "package": "com.google.relay.example.reflect.ui.components",
  "generateImplementation": true,
  "generatePreviews": false,
}

ไฟล์การแมปคอมโพเนนต์จะระบุเป้าหมายและแพ็กเกจคลาส Compose รวมถึงคอลเล็กชันออบเจ็กต์ fieldMapping ที่ไม่บังคับ การแมปช่องเหล่านี้ช่วยให้คุณเปลี่ยนพารามิเตอร์แพ็กเกจให้เป็นพารามิเตอร์ Compose ที่คาดไว้ได้ ในกรณีนี้ API จะเหมือนกัน คุณจึงต้องระบุเฉพาะคลาสเป้าหมายเท่านั้น

  1. สร้างโปรเจ็กต์อีกครั้ง
  2. ในไฟล์ trackersettings/ TrackerSettings.kt ให้ค้นหาฟังก์ชัน TitleFieldStyleFilledStateEnabledTextConfigurationsInputText() Composable ที่สร้างขึ้น และสังเกตว่ามีคอมโพเนนต์ ReflectTextField ที่สร้างขึ้น

TrackerSettings.kt (generated)

@Composable
fun TitleFieldStyleFilledStateEnabledTextConfigurationsInputText(
    onTitleChanged: (String) -> Unit,
    title: String,
    modifier: Modifier = Modifier
) {
    ReflectTextField(
        onChange = onTitleChanged,
        labelText = "Title",
        leadingIcon = "search",
        trailingIcon = "cancel",
        supportingText = "Supporting text",
        inputText = title,
        state = State.Enabled,
        textConfigurations = TextConfigurations.InputText,
        modifier = modifier.fillMaxWidth(1.0f).requiredHeight(56.0.dp)
    )
}
  1. สร้างโปรเจ็กต์อีกครั้ง ตอนนี้คุณสามารถโต้ตอบกับช่องการตั้งค่าอุปกรณ์ติดตามได้แล้ว หน้าจอแก้ไขเสร็จสมบูรณ์

8. แมปกับธีม Compose

โดยค่าเริ่มต้น Relay จะสร้างค่าตัวอักษรล้วนสำหรับสีและการจัดรูปแบบตัวอักษร วิธีนี้ช่วยให้มั่นใจได้ว่าคำแปลจะถูกต้อง แต่ป้องกันไม่ให้คอมโพเนนต์ใช้ระบบธีมของ Compose คุณจะเห็นได้ชัดเมื่อดูแอปในโหมดมืด

ตัวอย่างหน้าจอหลักที่ใช้โหมดมืดและแสดงสีไม่ถูกต้อง

คอมโพเนนต์การนําทางวันแทบมองไม่เห็นและสีไม่ถูกต้อง วิธีแก้ปัญหานี้คือให้ใช้ฟีเจอร์การแมปสไตล์ใน Relay เพื่อลิงก์สไตล์ Figma กับโทนสีของ Compose ในโค้ดที่สร้างขึ้น ซึ่งจะช่วยเพิ่มความสอดคล้องของภาพระหว่าง Relay กับคอมโพเนนต์ Material Design 3 และเปิดใช้การรองรับโหมดมืด

1fac916db14929bb.png

สร้างไฟล์การแมปสไตล์

  1. ใน Android Studio ให้ไปที่ไดเรกทอรี src/main/ui-package-resources แล้วสร้างไดเรกทอรีใหม่ชื่อ style-mappings ในไดเรกทอรีดังกล่าว ให้สร้างไฟล์ figma_styles.json ที่มีโค้ดต่อไปนี้

figma_styles.json

{
  "figma": {
    "colors": {
      "Reflect Light/background": "md.sys.color.background",
      "Reflect Dark/background": "md.sys.color.background",
      "Reflect Light/on-background": "md.sys.color.on-background",
      "Reflect Dark/on-background": "md.sys.color.on-background",
      "Reflect Light/surface": "md.sys.color.surface",
      "Reflect Dark/surface": "md.sys.color.surface",
      "Reflect Light/on-surface": "md.sys.color.on-surface",
      "Reflect Dark/on-surface": "md.sys.color.on-surface",
      "Reflect Light/surface-variant": "md.sys.color.surface-variant",
      "Reflect Dark/surface-variant": "md.sys.color.surface-variant",
      "Reflect Light/on-surface-variant": "md.sys.color.on-surface-variant",
      "Reflect Dark/on-surface-variant": "md.sys.color.on-surface-variant",
      "Reflect Light/primary": "md.sys.color.primary",
      "Reflect Dark/primary": "md.sys.color.primary",
      "Reflect Light/on-primary": "md.sys.color.on-primary",
      "Reflect Dark/on-primary": "md.sys.color.on-primary",
      "Reflect Light/primary-container": "md.sys.color.primary-container",
      "Reflect Dark/primary-container": "md.sys.color.primary-container",
      "Reflect Light/on-primary-container": "md.sys.color.on-primary-container",
      "Reflect Dark/on-primary-container": "md.sys.color.on-primary-container",
      "Reflect Light/secondary-container": "md.sys.color.secondary-container",
      "Reflect Dark/secondary-container": "md.sys.color.secondary-container",
      "Reflect Light/on-secondary-container": "md.sys.color.on-secondary-container",
      "Reflect Dark/on-secondary-container": "md.sys.color.on-secondary-container",
      "Reflect Light/outline": "md.sys.color.outline",
      "Reflect Dark/outline": "md.sys.color.outline",
      "Reflect Light/error": "md.sys.color.error",
      "Reflect Dark/error": "md.sys.color.error"
    },
    "typography": {
      "symbols": {
        "Reflect/headline/large": "md.sys.typescale.headline-large",
        "Reflect/headline/medium": "md.sys.typescale.headline-medium",
        "Reflect/headline/small": "md.sys.typescale.headline-small",
        "Reflect/title/large": "md.sys.typescale.title-large",
        "Reflect/title/medium": "md.sys.typescale.title-medium",
        "Reflect/title/small": "md.sys.typescale.title-small",
        "Reflect/body/large": "md.sys.typescale.body-large",
        "Reflect/body/medium": "md.sys.typescale.body-medium",
        "Reflect/body/small": "md.sys.typescale.body-small",
        "Reflect/label/large": "md.sys.typescale.label-large",
        "Reflect/label/medium": "md.sys.typescale.label-medium",
        "Reflect/label/small": "md.sys.typescale.label-small"
      },
      "subproperties": {
        "fontFamily": "font",
        "fontWeight": "weight",
        "fontSize": "size",
        "letterSpacing": "tracking",
        "lineHeightPx": "line-height"
      }
    }
  },
  "compose": {
    "colors": {
      "md.sys.color.background": "MaterialTheme.colorScheme.background",
      "md.sys.color.error": "MaterialTheme.colorScheme.error",
      "md.sys.color.error-container": "MaterialTheme.colorScheme.errorContainer",
      "md.sys.color.inverse-on-surface": "MaterialTheme.colorScheme.inverseOnSurface",
      "md.sys.color.inverse-surface": "MaterialTheme.colorScheme.inverseSurface",
      "md.sys.color.on-background": "MaterialTheme.colorScheme.onBackground",
      "md.sys.color.on-error": "MaterialTheme.colorScheme.onError",
      "md.sys.color.on-error-container": "MaterialTheme.colorScheme.onErrorContainer",
      "md.sys.color.on-primary": "MaterialTheme.colorScheme.onPrimary",
      "md.sys.color.on-primary-container": "MaterialTheme.colorScheme.onPrimaryContainer",
      "md.sys.color.on-secondary": "MaterialTheme.colorScheme.onSecondary",
      "md.sys.color.on-secondary-container": "MaterialTheme.colorScheme.onSecondaryContainer",
      "md.sys.color.on-surface": "MaterialTheme.colorScheme.onSurface",
      "md.sys.color.on-surface-variant": "MaterialTheme.colorScheme.onSurfaceVariant",
      "md.sys.color.on-tertiary": "MaterialTheme.colorScheme.onTertiary",
      "md.sys.color.on-tertiary-container": "MaterialTheme.colorScheme.onTertiaryContainer",
      "md.sys.color.outline": "MaterialTheme.colorScheme.outline",
      "md.sys.color.primary": "MaterialTheme.colorScheme.primary",
      "md.sys.color.primary-container": "MaterialTheme.colorScheme.primaryContainer",
      "md.sys.color.secondary": "MaterialTheme.colorScheme.secondary",
      "md.sys.color.secondary-container": "MaterialTheme.colorScheme.secondaryContainer",
      "md.sys.color.surface": "MaterialTheme.colorScheme.surface",
      "md.sys.color.surface-variant": "MaterialTheme.colorScheme.surfaceVariant",
      "md.sys.color.tertiary": "MaterialTheme.colorScheme.tertiary",
      "md.sys.color.tertiary-container": "MaterialTheme.colorScheme.tertiaryContainer"
    },
    "typography": {
      "symbols": {
        "md.sys.typescale.display-large": "MaterialTheme.typography.displayLarge",
        "md.sys.typescale.display-medium": "MaterialTheme.typography.displayMedium",
        "md.sys.typescale.display-small": "MaterialTheme.typography.displaySmall",
        "md.sys.typescale.headline-large": "MaterialTheme.typography.headlineLarge",
        "md.sys.typescale.headline-medium": "MaterialTheme.typography.headlineMedium",
        "md.sys.typescale.headline-small": "MaterialTheme.typography.headlineSmall",
        "md.sys.typescale.title-large": "MaterialTheme.typography.titleLarge",
        "md.sys.typescale.title-medium": "MaterialTheme.typography.titleMedium",
        "md.sys.typescale.title-small": "MaterialTheme.typography.titleSmall",
        "md.sys.typescale.body-large": "MaterialTheme.typography.bodyLarge",
        "md.sys.typescale.body-medium": "MaterialTheme.typography.bodyMedium",
        "md.sys.typescale.body-small": "MaterialTheme.typography.bodySmall",
        "md.sys.typescale.label-large": "MaterialTheme.typography.labelLarge",
        "md.sys.typescale.label-medium": "MaterialTheme.typography.labelMedium",
        "md.sys.typescale.label-small": "MaterialTheme.typography.labelSmall"
      },
      "subproperties": {
        "font": "fontFamily",
        "weight": "fontWeight",
        "size": "fontSize",
        "tracking": "letterSpacing",
        "line-height": "lineHeight"
      }
    },
    "options": {
      "packages": {
        "MaterialTheme": "androidx.compose.material3"
      }
    }
  }
}

ไฟล์การแมปธีมมีโครงสร้างที่มีออบเจ็กต์ระดับบนสุด 2 รายการ ได้แก่ figma และ compose ภายในออบเจ็กต์เหล่านี้ คำจำกัดความของสีและประเภทจะลิงก์กันระหว่าง 2 สภาพแวดล้อมผ่านโทเค็นกลาง ซึ่งช่วยให้สไตล์ Figma หลายสไตล์แมปกับรายการธีม Compose รายการเดียวได้ ซึ่งจะมีประโยชน์เมื่อคุณรองรับธีมสว่างและธีมมืด

  1. ตรวจสอบไฟล์การแมป โดยเฉพาะอย่างยิ่งวิธีแมปพร็อพเพอร์ตี้แบบอักษรจาก Figma ไปยังสิ่งที่ Compose คาดหวัง

นําเข้าแพ็กเกจ UI อีกครั้ง

หลังจากสร้างไฟล์การแมปแล้ว คุณต้องนําเข้าแพ็กเกจ UI ทั้งหมดกลับไปยังโปรเจ็กต์อีกครั้ง เนื่องจากระบบจะทิ้งค่าสไตล์ Figma ทั้งหมดเมื่อนําเข้าครั้งแรกเนื่องจากไม่มีไฟล์การแมป

หากต้องการนําเข้าแพ็กเกจ UI อีกครั้ง ให้ทําตามขั้นตอนต่อไปนี้

  1. ใน Android Studio ให้คลิกไฟล์ > ใหม่ > นําเข้าแพ็กเกจ UI กล่องโต้ตอบนําเข้าแพ็กเกจ UI จะปรากฏขึ้น
  2. ในกล่องข้อความ URL แหล่งที่มาของ Figma ให้ป้อน URL ของไฟล์ต้นทาง Figma
  3. เลือกช่องทำเครื่องหมายแปลสไตล์ Figma เป็นธีม Compose
  4. เลือกนําเข้าการกําหนดค่าที่กําหนดเอง คลิกไอคอนโฟลเดอร์ แล้วเลือกไฟล์ที่คุณเพิ่งสร้าง src/main/ui-package-resources/style-mappings/figma_styles.json
  5. คลิกถัดไป คุณจะเห็นตัวอย่างแพ็กเกจ UI ของไฟล์
  6. คลิกสร้าง ระบบจะนำเข้าแพ็กเกจไปยังโปรเจ็กต์

กล่องโต้ตอบ "นําเข้าแพ็กเกจ UI"

  1. โปรดสร้างโปรเจ็กต์อีกครั้ง แล้วเปิดไฟล์ switch/Switch.kt เพื่อดูโค้ดที่สร้างขึ้น

Switch.kt (สร้างขึ้น)

@Composable
fun ActiveOverlay(
    modifier: Modifier = Modifier,
    content: @Composable RelayContainerScope.() -> Unit
) {
    RelayContainer(
        backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
        isStructured = false,
        radius = 32.0,
        content = content,
        modifier = modifier.fillMaxWidth(1.0f).fillMaxHeight(1.0f)
    )
}
  1. สังเกตว่ามีการกําหนดค่าพารามิเตอร์ backgroundColor เป็นช่อง MaterialTheme.colorScheme.surfaceVariant อย่างไรในออบเจ็กต์ธีมการเขียน
  2. เรียกใช้โปรเจ็กต์และเปิดโหมดมืดในโปรแกรมจำลอง ธีมมีผลอย่างถูกต้องและข้อบกพร่องด้านภาพได้รับการแก้ไขแล้ว

6cf2aa19fabee292.png

9. ขอแสดงความยินดี

ยินดีด้วย คุณได้เรียนรู้วิธีผสานรวม Relay เข้ากับแอป Compose แล้ว

ดูข้อมูลเพิ่มเติม