Khi sử dụng WindowInsetsCompat
, ứng dụng của bạn có thể truy vấn và kiểm soát bàn phím ảo (còn gọi là IME) tương tự như cách tương tác với các thanh hệ thống. Ứng dụng của bạn cũng có thể sử dụng WindowInsetsAnimationCompat
để tạo hiệu ứng chuyển đổi liền mạch khi mở hoặc đóng bàn phím phần mềm.
Đ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 để hiển thị tràn viền. Điều này cho phép lớp này xử lý các phần lồng ghép cửa sổ hệ thống, chẳng hạn như các thanh hệ thống và bàn phím ảo.
Kiểm tra chế độ hiển thị của phần mềm bàn phím
Sử dụng WindowInsets
để kiểm tra chế độ hiển thị bàn phím phần mề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 về chế độ hiển thị của 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
Khi người dùng nhấn vào trường nhập văn bản, bàn phím sẽ trượt vào vị trí từ cuối màn hình, như trong ví dụ sau:
Ví dụ có nhãn "Không đồng bộ" trong hình 2 cho thấy hành vi 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 sẽ tự động căn chỉnh thay vì đồng bộ hoá với ảnh động của bàn phím – 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. Giao diện này trông mượt mà hơn, như 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ần đồ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 kỳ thay đổi nào về bố cục.
onPrepare
được gọi khi ảnh động lồng ghép bắt đầu và trước khi các thành phần hiển thị được bố trí lại do ảnh động. Bạn có thể sử dụng thuộc tính 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ị.
Đ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 lồng ghép bắt đầu. Bạn có thể sử dụng thuộc tính này để đặt tất cả các thuộc tính chế độ xem thành trạng thái kết thúc của các thay đổi về bố cục. Nếu bạn đặt lệnh gọi lại OnApplyWindowInsetsListener
thành bất kỳ thành phần hiển thị nào, thì lệnh gọi lại đó đã được gọi tại 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 các thuộc tính thành phần hiển thị.
Đ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 phần lồng ghép thay đổi trong quá trình chạy ảnh động, vì vậy, bạn có thể ghi đè phần lồng ghép đó và được thông báo trên mọi khung hình trong ảnh động bàn phím. Cập nhật các thuộc tính thành phần hiển thị để thành phần hiển thị tạo ảnh động đồng bộ với bàn phím.
Tất cả các 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
để dịch chuyển thành phần hiển thị, giá trị sẽ 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 đến 0
ở vị trí bố cục ban đầu.
Đ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
(không bắt buộc). Phương thức này được gọi sau khi ảnh động kết thúc. Đây là thời điểm thích hợp để xoá mọi thay đổi tạm thời.
Tài nguyên khác
- WindowInsetsAnimation trên GitHub.