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

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

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

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

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

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

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

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

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

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

แอปที่เสร็จสิ้น

สิ่งที่คุณต้องมี

2. ตั้งค่า

รับโค้ด

หากต้องการรับโค้ดสำหรับ Codelab นี้ ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้

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

ในทั้ง 2 กรณี Branch main จะมีโค้ดเริ่มต้นและ Branch ของ end จะมีโค้ดโซลูชัน

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

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

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

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

  1. หากเห็นกล่องโต้ตอบหมายเหตุความเป็นส่วนตัวของปลั๊กอินของบุคคลที่สาม ให้คลิกยอมรับ
  2. คลิก OK > รีสตาร์ท
  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 ให้วางโทเค็นเพื่อการเข้าถึงแล้วคลิกตกลง ตั้งค่าสภาพแวดล้อมแล้ว

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

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

ดูหน้าจอหลัก

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

หน้าจอหลัก

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

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

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

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

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

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

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

ตรวจสอบธีม

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

รูปแบบ Figma

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

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

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

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

88afd168463bf7e5.png

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

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

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 และทรัพยากร Dependency อยู่
  2. เปิดไฟล์ต้นฉบับ JSON โมดูล Relay จะแสดงตัวอย่างของแพ็กเกจและ API ของแพ็กเกจ

a6105146c4cfb47.png

สร้างโค้ด

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

c0d21ab0622ad550.png

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

ในส่วนนี้ คุณจะได้รายละเอียดเกี่ยวกับโค้ดที่สร้างขึ้นสำหรับตัวติดตามสวิตช์

การออกแบบตัวติดตามสวิตช์

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

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
  • องค์ประกอบย่อยจะแบ่งออกเป็น Composable แยกกัน
  • ระบบจะสร้างหน้าตัวอย่างที่ประกอบกันได้สำหรับการออกแบบรูปแบบต่างๆ ทั้งหมด
  • สีและรูปแบบตัวอักษรจะฮาร์ดโค้ดไว้ คุณแก้ไขปัญหานี้ในภายหลัง

ใส่อุปกรณ์ติดตาม

  1. ใน Android Studio ให้เปิดไฟล์ java/com/google/relay/example/reflect/ui/components/TrackerControl.kt ไฟล์นี้ให้ข้อมูลและตรรกะการโต้ตอบต่อเครื่องมือติดตามพฤติกรรม
  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. สร้างโปรเจ็กต์อีกครั้ง ตอนนี้หน้าแรกแสดงตัวติดตามสวิตช์ได้อย่างถูกต้องตามที่ออกแบบด้วยข้อมูลแบบเรียลไทม์

4241e78b9f82075b.png

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

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

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

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

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

  1. ใน Android Studio ให้เปิดไฟล์ java/com/google/relay/example/reflect/ui/components/SwitchControl.kt
  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 ด้วย Composable ที่มีอยู่ วิธีนี้เป็นวิธีที่ยอดเยี่ยมในการแสดงคอมโพเนนต์ที่พร้อมใช้งานทันที หรือแม้กระทั่งระบบการออกแบบที่กำหนดเองลงในโค้ดของคุณ

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. กล่องโต้ตอบไฟล์การแมปจะปรากฏขึ้น ป้อนตัวเลือกต่อไปนี้
  • ใน Target composable ให้เลือก Use available composable แล้วป้อน 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 ให้ค้นหาฟังก์ชัน Composable TitleFieldStyleFilledStateEnabledTextConfigurationsInputText() ที่สร้างขึ้น และสังเกตว่ามีคอมโพเนนต์ ReflectTextField ที่สร้างขึ้น

TrackerSettings.kt (สร้างแล้ว)

@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. แมปไปยังธีมการเขียน

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

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

คอมโพเนนต์การนำทางวันแทบจะมองไม่เห็นและสีไม่ถูกต้อง ในการแก้ปัญหานี้ คุณใช้ฟีเจอร์การแมปรูปแบบใน Relay เพื่อลิงก์รูปแบบ Figma กับโทเค็นของธีมในโค้ดที่สร้างขึ้น ซึ่งเป็นการเพิ่มความสอดคล้องกันของภาพระหว่างคอมโพเนนต์ 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 ภายในออบเจ็กต์เหล่านี้ คำจำกัดความของสีและประเภทจะเชื่อมโยงกันระหว่างสภาพแวดล้อมทั้งสองผ่านโทเค็นระดับกลาง วิธีนี้ช่วยให้สไตล์ Figma หลากหลายแบบแมปกับธีม Compose เพียงรายการเดียวได้ ซึ่งมีประโยชน์เมื่อคุณรองรับธีมสว่างและธีมมืด

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

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

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

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

  1. ใน Android Studio ให้คลิกไฟล์ > ใหม่ > นำเข้าแพ็กเกจ UI กล่องโต้ตอบนำเข้าแพ็กเกจ UI จะปรากฏขึ้น
  2. ในกล่องข้อความ URL แหล่งที่มาของ Figma ให้ป้อน URL ของไฟล์ต้นฉบับ Figma
  3. เลือกช่องทำเครื่องหมายแปลรูปแบบ Figma เป็นธีมการเขียน
  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 แล้ว

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