กู้คืนโฟกัส

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

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

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

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

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

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

คอนเทนเนอร์เลย์เอาต์แบบไม่เลื่อนมาตรฐาน เช่น Row และ Column จะไม่สร้างขอบเขตโฟกัสโดยค่าเริ่มต้น ซึ่งต่างจากคอนเทนเนอร์เลย์เอาต์แบบเลื่อน เนื่องจากตัวดัดแปลง 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()