WindowInsetsCompat kullanarak uygulamanız, sistem çubuklarıyla etkileşim kurma şekline benzer şekilde dokunmatik klavyeyi (IME olarak da bilinir) sorgulayabilir ve kontrol edebilir. Uygulamanız, yazılım klavyesi açıldığında veya kapatıldığında sorunsuz geçişler oluşturmak için
WindowInsetsAnimationCompat
de kullanabilir.
Ön koşullar
Yazılım klavyesi için kontrol ve animasyon ayarlamadan önce uygulamanızı uçtan uca gösterecek şekilde yapılandırın. Bu, sistem çubukları ve dokunmatik klavye gibi sistem penceresi yerleştirmelerinin işlenmesini sağlar.
Varsayılan senkronize edilmiş yerleştirme animasyonu
API düzeyi 37.2 ve sonraki sürümlerde, özel bir WindowInsetsAnimationCompat.Callback uygulamadan varsayılan pencere düzeni ayarlamalarını (ör. SOFT_INPUT_ADJUST_RESIZE veya SOFT_INPUT_ADJUST_PAN, WindowInsetsController.show(WindowInsets.Type.ime()) kullanılarak IME gösterilirken) kullanan uygulamalar, sistem düzeyinde senkronize edilmiş kare kare animasyonlardan yararlanabilir. Etkinleştirildiğinde bu özellik, her kareye otomatik olarak iç kısımlar uygular ve klavye hareket ederken sorunsuz bir geçiş sağlamak için düzen geçişini tetikler.
Bu davranışı etkinleştirmek için AndroidManifest.xml dosyasındaki etkinliğinize veya uygulamanıza aşağıdaki <property> etiketini ekleyin:
<property
android:name="android.window.PROPERTY_COMPAT_ALLOW_SYNCHRONIZED_INSETS_ANIMATION"
android:value="true" />
Ana iş parçacığı dışında ekleme animasyonları gerçekleştirme
Varsayılan olarak, WindowInsetsAnimationCompat.Callback kaydetmek, pencere yerleştirme animasyonunun uygulamanın ana iş parçacığında çalışmasını zorunlu kılar. Uygulamanız animasyon sırasında görünüm düzenini sürekli olarak güncelleyip senkronize ediyorsa (ör. onProgress yönteminde olduğu gibi) bu gereklidir. Ancak uygulamanızın yalnızca yaşam döngüsü geçişlerini (ör. IME animasyonunun başlatılması veya sonlandırılması) dinlemesi gerekiyorsa ve görünümleri kare kare güncellemesi gerekmiyorsa ana iş parçacığında çalışmak gereksiz ek yüke ve animasyon takılmalarına neden olabilir. Bu durum, özellikle ana iş parçacığı başka bir işlemle meşgulse geçerlidir.
API düzeyi 37.2 ve sonraki sürümlerde, bu geçişleri gözlemlemek için
ViewTreeObserver.WindowInsetsAnimationListener
kullanabilirsiniz. Bu işleyici, kare kare ilerleme durumu güncellemeleri almadığından (onProgress geri çağırma yok) sistem, ana iş parçacığı yerine özel bir animasyon iş parçacığında yerleştirme animasyonunu çalıştırabilir. Bu da daha sorunsuz bir geçiş sağlar.
Kotlin
val listener = object : ViewTreeObserver.WindowInsetsAnimationListener { override fun onPrepare(animation: WindowInsetsAnimation) { // Handle preparation before animation starts } override fun onEnd(animation: WindowInsetsAnimation) { // Clean up temporary changes } } // Add the listener view.viewTreeObserver.addWindowInsetsAnimationListener(listener) // Remove the listener when no longer needed view.viewTreeObserver.removeWindowInsetsAnimationListener(listener)
Java
ViewTreeObserver.WindowInsetsAnimationListener listener = new ViewTreeObserver.WindowInsetsAnimationListener() { @Override public void onPrepare(@NonNull WindowInsetsAnimation animation) { // Handle preparation before animation starts } @Override public void onEnd(@NonNull WindowInsetsAnimation animation) { // Clean up temporary changes } }; // Add the listener view.getViewTreeObserver().addWindowInsetsAnimationListener(listener); // Remove the listener when no longer needed view.getViewTreeObserver().removeWindowInsetsAnimationListener(listener);
Klavye yazılımının görünürlüğünü kontrol etme
Yazılım klavyesinin görünürlüğünü kontrol etmek için WindowInsets simgesini kullanın.
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;
Alternatif olarak, yazılım klavyesi görünürlüğündeki değişiklikleri gözlemlemek için
ViewCompat.setOnApplyWindowInsetsListener
kullanabilirsiniz.
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; });
Animasyonu yazılım klavyesiyle senkronize etme
Bir kullanıcının metin giriş alanına dokunması, klavyenin ekranın alt kısmından yerine kaymasına neden olur. Bu durum aşağıdaki örnekte gösterilmiştir:
Şekil 2'deki "Senkronize edilmemiş" etiketli örnekte, Android 10'daki (API düzeyi 29) varsayılan davranış gösterilmektedir. Bu davranışta, metin alanı ve uygulamanın içeriği klavyenin animasyonuyla senkronize olmak yerine yerine oturur. Bu davranış görsel olarak rahatsız edici olabilir.
Android 11 (API düzeyi 30) ve sonraki sürümlerde, uygulamanın geçişini klavyenin ekranın alt kısmından yukarı ve aşağı kaymasıyla senkronize etmek için
WindowInsetsAnimationCompatkullanabilirsiniz. Bu, Şekil 2'deki "Senkronize" etiketli örnekte gösterildiği gibi daha sorunsuz görünür.
Klavye animasyonuyla senkronize edilecek görünümü kullanarak
WindowInsetsAnimationCompat.Callback
yapılandırın.
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 içinde geçersiz kılmak için çeşitli yöntemler vardır:
onPrepare(),
onStart(),
onProgress(),
ve
onEnd().
Düzen değişikliklerinden önce onPrepare() ile aramaya başlayın.
onPrepare, bir içe yerleştirme animasyonu başlatıldığında ve görünümler animasyon nedeniyle yeniden düzenlenmeden önce çağrılır. Bu işlevi, başlangıç durumunu (bu örnekte görünümün alt koordinatı) kaydetmek için kullanabilirsiniz.
onPrepare() kullanılır.
Aşağıdaki snippet'te onPrepare için örnek bir çağrı gösterilmektedir:
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(); }
Bir içe yerleştirme animasyonu başladığında onStart çağrılır. Tüm görünüm özelliklerini düzen değişikliklerinin son durumuna ayarlamak için bu özelliği kullanabilirsiniz. Görünümlerden herhangi birine ayarlanmış bir OnApplyWindowInsetsListener geri çağırma varsa bu noktada zaten çağrılmıştır. Bu, görünüm özelliklerinin son durumunu kaydetmek için uygun bir zamandır.
onStart() kullanarak bitiş durumunu kaydetme.
Aşağıdaki snippet'te onStart için örnek bir çağrı gösterilmektedir:
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, animasyon çalıştırılırken dolgular değiştiğinde çağrılır. Bu nedenle, klavye animasyonu sırasında her karede geçersiz kılabilir ve bildirim alabilirsiniz. Görünüm özelliklerini, görünümün klavye ile senkronize olacak şekilde animasyon oluşturacak şekilde güncelleyin.
Bu noktada tüm düzen değişiklikleri tamamlanmıştır. Örneğin, görünümü kaydırmak için View.translationY kullanırsanız bu yöntemin her çağrısında değer kademeli olarak azalır ve sonunda orijinal düzen konumunda 0 değerine ulaşır.
onProgress() kullanma.
Aşağıdaki snippet'te onProgress için örnek bir çağrı gösterilmektedir:
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; }
İsteğe bağlı olarak onEnd değerini geçersiz kılabilirsiniz. Bu yöntem, animasyon sona erdikten sonra çağrılır. Bu, geçici değişiklikleri temizlemek için uygun bir zamandır.
Ek kaynaklar
- GitHub'da WindowInsetsAnimation.