Bằng cách sử dụng WindowInsetsCompat
,
ứng dụng của bạn có thể truy vấn và điều khiển bàn phím ảo (còn được gọi là
IME) tương tự như
tương tác với thanh hệ thống. Ứng dụng của bạn cũng có thể sử dụng
WindowInsetsAnimationCompat
để tạo chuyển đổi liền mạch khi bàn phím phần mềm mở hoặc đóng.
Điều kiện tiên quyết
Trước khi thiết lập chế độ điều khiển và ảnh động cho bàn phím phần mềm, hãy định cấu hình ứng dụng của bạn để hiển thị tràn viền. Điều này cho phép nó xử lý các phần lồng ghép cửa sổ hệ thống, chẳng hạn như thanh hệ thống và bàn phím ảo.
Kiểm tra chế độ hiển thị phần mềm bàn phím
Sử dụng WindowInsets
để kiểm tra phần mềm
chế độ hiển thị bàn phím.
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;
Ngoài ra, bạn có thể sử dụng
ViewCompat.setOnApplyWindowInsetsListener
để quan sát những thay đổi đối với chế độ hiển thị bàn phím phần mềm.
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; });
Đồng bộ hoá ảnh động với bàn phím phần mềm
Người dùng nhấn vào trường nhập văn bản khiến bàn phím trượt vào vị trí cuối màn hình, như trong ví dụ sau:
Ví dụ có nhãn "Chưa đồng bộ hoá" trong hình 2 cho thấy chế độ mặc định trong Android 10 (API cấp 29), trong đó trường văn bản và nội dung của ứng dụng bám vào đúng vị trí thay vì đồng bộ hoá bằng ảnh động – hành vi có thể gây khó chịu về mặt hình ảnh.
Trong Android 11 (API cấp 30) trở lên, bạn có thể sử dụng
WindowInsetsAnimationCompat
để đồng bộ hoá quá trình chuyển đổi của ứng dụng với bàn phím trượt lên và xuống từ cuối màn hình. Kiểu này mượt mà hơn, như được minh hoạ trong ví dụ có nhãn "Đồng bộ hoá" trong hình 2.
Định cấu hình
WindowInsetsAnimationCompat.Callback
với chế độ xem được đồng bộ hoá với ảnh động bàn phím.
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. });
Có một số phương thức để ghi đè trong WindowInsetsAnimationCompat.Callback
,
cụ thể là
onPrepare()
,
onStart()
,
onProgress()
,
và
onEnd()
.
Bắt đầu bằng cách gọi onPrepare()
trước khi có bất cứ thay đổi nào về bố cục.
onPrepare
được gọi khi ảnh động phần lồng ghép bắt đầu và trước khung hiển thị
được sắp xếp lại do hoạt ảnh. Bạn có thể sử dụng hàm này để lưu trạng thái bắt đầu,
trong trường hợp này là toạ độ dưới cùng của thành phần hiển thị.
![Hình ảnh cho thấy toạ độ dưới cùng của trạng thái bắt đầu của chế độ xem gốc.](https://developer.android.com/static/images/guide/navigation/software-keyboard-3.png?authuser=9&hl=vi)
onPrepare()
để
ghi lại trạng thái bắt đầu.
Đoạn mã sau đây cho thấy một lệnh gọi mẫu đến 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
được gọi khi ảnh động phần lồng ghép bắt đầu. Bạn có thể dùng mật khẩu này để đặt tất cả
thuộc tính khung hiển thị sang trạng thái kết thúc của bố cục sẽ thay đổi. Nếu bạn có
Lệnh gọi lại OnApplyWindowInsetsListener
được đặt thành bất kỳ khung hiển thị nào, phương thức này đã được đặt
được gọi vào thời điểm này. Đây là thời điểm thích hợp để lưu trạng thái kết thúc của chế độ xem
các thuộc tính.
![Hình ảnh thể hiện toạ độ dưới cùng trạng thái kết thúc của chế độ xem](https://developer.android.com/static/images/guide/navigation/software-keyboard-4.png?authuser=9&hl=vi)
onStart()
để ghi
trạng thái kết thúc.
Đoạn mã sau đây cho thấy một lệnh gọi mẫu đến 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
được gọi khi các phần lồng ghép thay đổi trong quá trình chạy ảnh động,
để bạn có thể ghi đè và nhận thông báo trên mọi khung hình trong khi dùng bàn phím
ảnh động. Cập nhật các thuộc tính khung hiển thị để khung hiển thị tạo hiệu ứng động trong
đồng bộ hoá với bàn phím.
Mọi thay đổi về bố cục đã hoàn tất tại thời điểm này. Ví dụ: nếu bạn sử dụng
View.translationY
để di chuyển chế độ xem, giá trị này giảm dần cho mỗi
lệnh gọi của phương thức này và cuối cùng đạt 0
đến vị trí bố cục ban đầu.
onProgress()
để
đồng bộ hoá ảnh động.
Đoạn mã sau đây cho thấy một lệnh gọi mẫu đến 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; }
Bạn có thể ghi đè onEnd
nếu muốn. Phương thức này được gọi sau ảnh động
đã kết thúc. Đây là thời điểm thích hợp để dọn dẹp mọi thay đổi tạm thời.
Tài nguyên khác
- WindowInsetsAnimation trên GitHub.