Yazılım klavyesini kontrol etme ve animasyon çalıştırma

Yazma yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Oluşturma penceresinde klavyeyle nasıl çalışacağınızı öğrenin.

WindowInsetsCompat'yi 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.

1.şekil Yazılım klavyesinin açık-kapalı geçişine iki örnek.

Ö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şimlerinin işlenmesini sağlar.

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 kayarak yerine oturmasına neden olur. Bu durum aşağıdaki örnekte gösterilmiştir:

Şekil 2. Senkronize klavye animasyonu.
  • Ş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 WindowInsetsAnimationCompat kullanabilirsiniz. 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. Örneğin onPrepare(), onStart(), onProgress(), ve onEnd(). Düzen değişikliklerinden önce onPrepare() ile aramaya başlayın.

onPrepare, bir iç kenar 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.

Kök görünümün başlangıç durumu alt koordinatını gösteren resim.
3.şekil Başlangıç durumunu kaydetmek için 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 arama varsa bu noktada zaten çağrılmıştır. Bu, görünüm özelliklerinin son durumunu kaydetmek için iyi bir zamandır.

Görünümün son durumdaki alt koordinatını gösteren resim
4.şekil Bitiş durumunu kaydetmek için onStart() kullanma.

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 yerleşimler 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 konumuna ulaşmak için 0 olur.

Şekil 5. Animasyonları senkronize etmek için 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 geçersiz kılabilirsiniz. Bu yöntem, animasyon sona erdikten sonra çağrılır. Bu, geçici değişiklikleri temizlemek için iyi bir zamandır.

Ek kaynaklar