เมื่อใช้ WindowInsetsCompat
แอปจะค้นหาและควบคุมแป้นพิมพ์บนหน้าจอ (หรือที่เรียกว่า IME) ได้คล้ายกับวิธีที่โต้ตอบกับแถบระบบ นอกจากนี้ แอปยังใช้ WindowInsetsAnimationCompat
เพื่อสร้างการเปลี่ยนที่ราบรื่นเมื่อเปิดหรือปิดแป้นพิมพ์ซอฟต์แวร์ได้ด้วย
สิ่งที่ต้องมีก่อน
ก่อนตั้งค่าการควบคุมและภาพเคลื่อนไหวสำหรับแป้นพิมพ์ซอฟต์แวร์ ให้กำหนดค่าแอปให้แสดงแบบเต็มหน้าจอ ซึ่งจะช่วยให้จัดการส่วนแทรกของหน้าต่างระบบได้ เช่น แถบระบบและแป้นพิมพ์บนหน้าจอ
ตรวจสอบการแสดงซอฟต์แวร์แป้นพิมพ์
ใช้ WindowInsets
เพื่อตรวจสอบระดับการมองเห็นแป้นพิมพ์ของซอฟต์แวร์
Kotlin
val insets = ViewCompat.getRootWindowInsets(view) ?: return val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()) val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
Java
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(view); boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
หรือจะใช้ ViewCompat.setOnApplyWindowInsetsListener
เพื่อดูการเปลี่ยนแปลงการแสดงผลแป้นพิมพ์ซอฟต์แวร์ก็ได้
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -> val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()) val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom insets }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; return insets; });
ซิงค์ภาพเคลื่อนไหวกับแป้นพิมพ์ซอฟต์แวร์
เมื่อผู้ใช้แตะช่องป้อนข้อความ แป้นพิมพ์จะเลื่อนขึ้นมาจากด้านล่างของหน้าจอดังที่แสดงในตัวอย่างต่อไปนี้
ตัวอย่างที่มีป้ายกำกับว่า "ไม่ได้ซิงค์" ในรูปที่ 2 แสดงลักษณะการทำงานเริ่มต้นใน Android 10 (API ระดับ 29) ซึ่งช่องข้อความและเนื้อหาของแอปจะปรากฏขึ้นแทนที่จะซิงค์กับภาพเคลื่อนไหวของแป้นพิมพ์ ซึ่งเป็นลักษณะการทำงานที่อาจทำให้ภาพดูไม่สอดคล้องกัน
ใน Android 11 (API ระดับ 30) ขึ้นไป คุณสามารถใช้
WindowInsetsAnimationCompat
เพื่อซิงค์การเปลี่ยนแอปกับแป้นพิมพ์ที่เลื่อนขึ้นและลงจากด้านล่างของหน้าจอ ซึ่งดูราบรื่นกว่า ดังที่แสดงในตัวอย่างที่มีป้ายกำกับว่า "ซิงค์แล้ว" ในรูปที่ 2
กำหนดค่า
WindowInsetsAnimationCompat.Callback
กับมุมมองเพื่อให้ซิงค์กับภาพเคลื่อนไหวของแป้นพิมพ์
Kotlin
ViewCompat.setWindowInsetsAnimationCallback( view, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) { // Override methods. } )
Java
ViewCompat.setWindowInsetsAnimationCallback( view, new WindowInsetsAnimationCompat.Callback( WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP ) { // Override methods. });
การลบล้างใน WindowInsetsAnimationCompat.Callback
ทำได้หลายวิธี ดังนี้
onPrepare()
onStart()
onProgress()
และ
onEnd()
เริ่มต้นด้วยการเรียกใช้ onPrepare()
ก่อนการเปลี่ยนแปลงเลย์เอาต์
onPrepare
จะเรียกใช้เมื่อภาพเคลื่อนไหวของส่วนแทรกเริ่มขึ้นและก่อนที่มุมมองจะจัดวางใหม่เนื่องจากภาพเคลื่อนไหว คุณสามารถใช้เพื่อบันทึกสถานะเริ่มต้น ซึ่งในกรณีนี้คือพิกัดด้านล่างของมุมมอง
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการเรียกใช้ onPrepare
Kotlin
var startBottom = 0f override fun onPrepare( animation: WindowInsetsAnimationCompat ) { startBottom = view.bottom.toFloat() }
Java
float startBottom; @Override public void onPrepare( @NonNull WindowInsetsAnimationCompat animation ) { startBottom = view.getBottom(); }
onStart
จะเรียกใช้เมื่อภาพเคลื่อนไหวของส่วนแทรกเริ่มขึ้น คุณสามารถใช้เพื่อตั้งค่าพร็อพเพอร์ตี้มุมมองทั้งหมดเป็นสถานะสุดท้ายของการเปลี่ยนแปลงเลย์เอาต์ หากคุณตั้งค่าการเรียกกลับ OnApplyWindowInsetsListener
ให้กับมุมมองใดก็ตาม ระบบจะเรียกใช้การเรียกกลับแล้ว ณ จุดนี้ ตอนนี้เป็นโอกาสที่ดีในการบันทึกสถานะสุดท้ายของพร็อพเพอร์ตี้มุมมอง
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการเรียกใช้ onStart
Kotlin
var endBottom = 0f override fun onStart( animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat ): WindowInsetsAnimationCompat.BoundsCompat { // Record the position of the view after the IME transition. endBottom = view.bottom.toFloat() return bounds }
Java
float endBottom; @NonNull @Override public WindowInsetsAnimationCompat.BoundsCompat onStart( @NonNull WindowInsetsAnimationCompat animation, @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds ) { endBottom = view.getBottom(); return bounds; }
onProgress
จะเรียกใช้เมื่อมีการใส่ข้อความบางส่วนที่เปลี่ยนแปลงไปเป็นส่วนหนึ่งของการแสดงภาพเคลื่อนไหว เพื่อให้คุณลบล้างและได้รับการแจ้งเตือนในทุกเฟรมระหว่างภาพเคลื่อนไหวของแป้นพิมพ์ อัปเดตพร็อพเพอร์ตี้ของมุมมองเพื่อให้มุมมองเคลื่อนไหวพร้อมกับแป้นพิมพ์
การเปลี่ยนแปลงเลย์เอาต์ทั้งหมดเสร็จสมบูรณ์แล้วในตอนนี้ เช่น หากคุณใช้ View.translationY
เพื่อเลื่อนมุมมอง ค่าจะค่อยๆ ลดลงทุกครั้งที่เรียกใช้เมธอดนี้ และในที่สุดจะไปถึง 0
ซึ่งเป็นตําแหน่งเลย์เอาต์เดิม
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการเรียกใช้ onProgress
Kotlin
override fun onProgress( insets: WindowInsetsCompat, runningAnimations: MutableList<WindowInsetsAnimationCompat> ): WindowInsetsCompat { // Find an IME animation. val imeAnimation = runningAnimations.find { it.typeMask and WindowInsetsCompat.Type.ime() != 0 } ?: return insets // Offset the view based on the interpolated fraction of the IME animation. view.translationY = (startBottom - endBottom) * (1 - imeAnimation.interpolatedFraction) return insets }
Java
@NonNull @Override public WindowInsetsCompat onProgress( @NonNull WindowInsetsCompat insets, @NonNull List<WindowInsetsAnimationCompat> runningAnimations ) { // Find an IME animation. WindowInsetsAnimationCompat imeAnimation = null; for (WindowInsetsAnimationCompat animation : runningAnimations) { if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) { imeAnimation = animation; break; } } if (imeAnimation != null) { // Offset the view based on the interpolated fraction of the IME animation. view.setTranslationY((startBottom - endBottom) * (1 - imeAnimation.getInterpolatedFraction())); } return insets; }
คุณลบล้าง onEnd
หรือไม่ก็ได้ ระบบจะเรียกใช้เมธอดนี้หลังจากภาพเคลื่อนไหวสิ้นสุดลง นี่เป็นโอกาสที่ดีในการล้างการเปลี่ยนแปลงชั่วคราว
แหล่งข้อมูลเพิ่มเติม
- WindowInsetsAnimation ใน GitHub