กู้คืนโฟกัส

เมื่อผู้ใช้ไปยังส่วนต่างๆ ของอินเทอร์เฟซผู้ใช้ที่ซับซ้อนโดยใช้แป้นพิมพ์ฮาร์ดแวร์หรือ D-pad ผู้ใช้มักจะย้ายไปมาระหว่างส่วนต่างๆ ของหน้าจอ เช่น ข้ามจากแถบนำทางด้านข้างไปยังรายการเนื้อหา โต้ตอบกับรายการ แล้วข้ามกลับมา การคืนค่าโฟกัสช่วยให้คอนเทนเนอร์จดจำองค์ประกอบย่อยที่โฟกัสก่อนหน้านี้และคืนค่าโฟกัสให้กับองค์ประกอบนั้นเมื่อโฟกัสกลับเข้าสู่คอนเทนเนอร์อีกครั้ง

คืนค่าโฟกัสในคอนเทนเนอร์ที่เลื่อนได้

ใน Jetpack Compose คอนเทนเนอร์ที่เลื่อนได้ เช่น LazyColumn, LazyRow และ LazyVerticalGrid จะทำหน้าที่เป็นกลุ่มโฟกัสโดยอัตโนมัติ หากต้องการเปิดใช้การคืนค่าโฟกัสในรายการหรือตารางกริดแบบ Lazy ให้แนบตัวแก้ไข focusRestorer ดังนี้

LazyColumn(
    modifier = Modifier.focusRestorer()
) {
    items(items) { item ->
        Button(onClick = { /* Handle click */ }) {
            Text(item)
        }
    }
}

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

คืนค่าโฟกัสในแถวและคอลัมน์

คอนเทนเนอร์เลย์เอาต์แบบไม่เลื่อนมาตรฐาน เช่น Row และ Column จะไม่สร้างขอบเขตโฟกัสโดยค่าเริ่มต้น ซึ่งแตกต่างจากคอนเทนเนอร์เลย์เอาต์แบบ Lazy เนื่องจากองค์ประกอบเหล่านี้ไม่ได้ขัดขวางเหตุการณ์การเข้าสู่โฟกัสด้วยตัวเอง การใช้ตัวแก้ไข focusRestorer เพียงอย่างเดียวจึงไม่เพียงพอ

หากต้องการเปิดใช้การคืนค่าโฟกัสใน Row หรือ Column ให้รวม focusGroup เข้ากับ focusRestorer ดังนี้

Row(
    modifier = Modifier
        .focusGroup()
        .focusRestorer()
) {
    Button(onClick = { /* Action 1 */ }) {
        Text("First item")
    }
    Button(onClick = { /* Action 2 */ }) {
        Text("Second item")
    }
    Button(onClick = { /* Action 3 */ }) {
        Text("Third item")
    }
}

ระบุเป้าหมายโฟกัสสำรอง

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

คุณสามารถปรับแต่งคอมโพเนนต์ย่อยที่จะได้รับโฟกัสเมื่อเข้าสู่ระบบครั้งแรกได้โดยส่ง FocusRequester สำรองไปยัง focusRestorer (หรือ Lambda ที่แสดงผล FocusRequester ใน Compose เวอร์ชันก่อนหน้า) ดังนี้

val firstItemRequester = remember { FocusRequester() }

LazyColumn(
    modifier = Modifier.focusRestorer(firstItemRequester)
) {
    itemsIndexed(items) { index, item ->
        val itemModifier = if (index == 0) {
            Modifier.focusRequester(firstItemRequester)
        } else {
            Modifier
        }
        Button(
            onClick = { /* Handle click */ },
            modifier = itemModifier
        ) {
            Text(item)
        }
    }
}

หากไม่มีองค์ประกอบย่อยที่โฟกัสไว้ก่อนหน้านี้ (หรือหากการคืนค่าโฟกัสไม่สำเร็จ) Compose จะย้ายโฟกัสไปยังเป้าหมายสำรองที่เชื่อมโยง

ในคอมโพเนนต์การนำทาง เช่น NavigationRail, NavigationBar, NavigationDrawer หรือ TabRow ผู้ใช้คาดหวังให้โฟกัสไปที่ปลายทางที่เลือกไว้ในปัจจุบันเมื่อเข้าสู่คอมโพเนนต์จากพื้นที่เนื้อหา

คุณสามารถกำหนดโฟกัสไปยังปลายทางที่ใช้งานอยู่ได้โดยรวม Modifier.focusGroup() เข้ากับ focusProperties และตั้งค่าพร็อพเพอร์ตี้ onEnter (หรือ enter ใน Compose เวอร์ชันก่อนหน้า) ดังนี้

val (homeRequester, searchRequester, settingsRequester) = remember { FocusRequester.createRefs() }

val selectedRequester = when (currentDestination) {
    "home" -> homeRequester
    "search" -> searchRequester
    "settings" -> settingsRequester
    else -> homeRequester
}

NavigationRail(
    modifier = modifier
        .focusProperties {
            // Redirect focus to the selected item when focus enters the navigation rail
            onEnter = { selectedRequester.requestFocus() }
        }
        .focusGroup()
) {
    NavigationRailItem(
        selected = currentDestination == "home",
        onClick = { onNavigate("home") },
        icon = { Icon(Icons.Default.Home, contentDescription = "Home") },
        label = { Text("Home") },
        modifier = Modifier.focusRequester(homeRequester)
    )
    NavigationRailItem(
        selected = currentDestination == "search",
        onClick = { onNavigate("search") },
        icon = { Icon(Icons.Default.Search, contentDescription = "Search") },
        label = { Text("Search") },
        modifier = Modifier.focusRequester(searchRequester)
    )
    NavigationRailItem(
        selected = currentDestination == "settings",
        onClick = { onNavigate("settings") },
        icon = { Icon(Icons.Default.Settings, contentDescription = "Settings") },
        label = { Text("Settings") },
        modifier = Modifier.focusRequester(settingsRequester)
    )
}

คืนค่าโฟกัสเมื่อเปลี่ยนหน้าจอ

เมื่อผู้ใช้คลิกรายการเพื่อไปยังหน้าจอรายละเอียดและกลับมาโดยใช้ปุ่มย้อนกลับหรือท่าทางสัมผัส คุณสามารถคืนค่าโฟกัสไปยังรายการที่ผู้ใช้คลิกได้

วิธีคงและคืนค่าโฟกัสในการเปลี่ยนหน้าจอ

  1. เชื่อมโยงคอนเทนเนอร์กับ FocusRequester
  2. ก่อนทริกเกอร์เหตุการณ์การนําทาง ให้เรียกใช้ saveFocusedChild() ใน FocusRequester ของคอนเทนเนอร์
  3. เมื่อผู้ใช้กลับไปที่หน้าจอ ให้ขอโฟกัสเริ่มต้นที่คอนเทนเนอร์หรือเรียกใช้ restoreFocusedChild()