การจัดการแป้นพิมพ์ที่ถอดออกได้

ไอคอนการให้ดาว 3 ดวง

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

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

แนวทางปฏิบัติแนะนำ

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

การรองรับแป้นพิมพ์ภายนอกเกี่ยวข้องกับการเปลี่ยนแปลงการกำหนดค่า ซึ่งคุณสามารถจัดการได้ 2 วิธีดังนี้

  1. ปล่อยให้ระบบสร้างกิจกรรมที่กำลังทำงานอยู่ขึ้นมาใหม่ และคุณเป็นผู้จัดการสถานะของแอป
  2. จัดการการเปลี่ยนแปลงการกำหนดค่าด้วยตนเอง (ระบบจะไม่สร้างกิจกรรมขึ้นมาใหม่) โดยทำดังนี้
    • ประกาศค่าการกำหนดค่าทั้งหมดที่เกี่ยวข้องกับแป้นพิมพ์
    • สร้างเครื่องจัดการการเปลี่ยนแปลงการกำหนดค่า

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

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

ใน Jetpack Compose คุณสามารถตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าแป้นพิมพ์ได้ 2 วิธีดังนี้

  1. UI แบบรีแอ็กทีฟ: อ่านสถานะการกำหนดค่าปัจจุบันโดยตรงใน Composable โดยใช้ LocalConfiguration.current UI จะจัดองค์ประกอบใหม่โดยอัตโนมัติเพื่อปรับให้เข้ากับสถานะใหม่เมื่อต่อหรือถอดแป้นพิมพ์
  2. Callback ของผลข้างเคียง: ใช้ DisposableEffect ที่รับรู้ถึงวงจรเพื่อลงทะเบียน Listener การเปลี่ยนแปลงการกำหนดค่าในกิจกรรมโฮสต์ ซึ่งช่วยให้คุณทริกเกอร์เหตุการณ์ที่ไม่ใช่ UI (เช่น การบันทึกหรือการวิเคราะห์) ได้โดยไม่ต้องสร้างกิจกรรมใหม่หรือสร้างอินสแตนซ์องค์ประกอบมุมมองจำลอง

ส่วนผสม

  • android:configChanges: แอตทริบิวต์ขององค์ประกอบ <activity> ในไฟล์ Manifest ของแอป แจ้งให้ระบบทราบเกี่ยวกับการเปลี่ยนแปลงการกำหนดค่าที่แอปจัดการ
  • LocalConfiguration: ผู้ให้บริการในพื้นที่ที่ประกอบกันได้ซึ่งแสดง Configuration ของอุปกรณ์ปัจจุบัน
  • DisposableEffect: API ผลข้างเคียงของ Compose ที่เรียกใช้บล็อกโค้ดเมื่อ Composable เข้าสู่ Composition และล้างข้อมูลเมื่อออกจาก Composition

ขั้นตอน

ประกาศแอตทริบิวต์ configChanges และเพิ่มค่าที่เกี่ยวข้องกับแป้นพิมพ์เพื่อป้องกันการสร้างกิจกรรมขึ้นมาใหม่ จากนั้นใช้ LocalConfiguration.current เพื่อปรับเลย์เอาต์ Composable แบบไดนามิก หรือลงทะเบียน Listener การกำหนดค่าโดยใช้ DisposableEffect

1. ประกาศแอตทริบิวต์ configChanges

อัปเดตองค์ประกอบ <activity> ในไฟล์ Manifest ของแอปโดยเพิ่มค่า keyboard|keyboardHidden ลงในรายการการเปลี่ยนแปลงการกำหนดค่าที่จัดการแล้ว ดังนี้

<activity
      …
      android:configChanges="...|keyboard|keyboardHidden">

2. ตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าแป้นพิมพ์

หากต้องการจัดการการเปลี่ยนแปลงการกำหนดค่าใน Jetpack Compose ให้ใช้ตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้ โดยขึ้นอยู่กับว่าคุณกำลังอัปเดต UI หรือเรียกใช้ Callback ของผลข้างเคียง

  • ตัวเลือก ก: UI แบบรีแอ็กทีฟ (แนะนำ)

    อ่านประเภทแป้นพิมพ์โดยตรงจาก LocalConfiguration.current เมื่อต่อหรือถอดแป้นพิมพ์ฮาร์ดแวร์ ค่านี้จะเปลี่ยนไป และ Compose จะจัดองค์ประกอบ UI ใหม่โดยอัตโนมัติ

    val configuration = LocalConfiguration.current
    val isPhysicalKeyboardAttached = configuration.keyboard == Configuration.KEYBOARD_QWERTY
    
    if (isPhysicalKeyboardAttached) {
        // Render layout optimized for physical keyboard
    } else {
        // Render default layout
    }

  • ตัวเลือก ข: Side-Effect Listener

    หากต้องการเรียกใช้ผลข้างเคียง (เช่น การบันทึก การอัปเดตฐานข้อมูลในเครื่อง หรือการเรียกใช้การวิเคราะห์) เมื่อการกำหนดค่ามีการเปลี่ยนแปลง ให้ใช้ DisposableEffect เพื่อลงทะเบียน Listener การเปลี่ยนแปลงการกำหนดค่าในโฮสต์ ComponentActivity

    val context = LocalActivity.current
    DisposableEffect(context) {
        val activity = context as? ComponentActivity
        val listener = Consumer<Configuration> { newConfig ->
            val hasKeyboard = newConfig.keyboard == Configuration.KEYBOARD_QWERTY
            // Trigger non-UI actions, analytics, etc.
        }
        activity?.addOnConfigurationChangedListener(listener)
        onDispose {
            activity?.removeOnConfigurationChangedListener(listener)
        }
    }

ผลลัพธ์

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

แหล่งข้อมูลเพิ่มเติม

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