सॉफ़्टवेयर कीबोर्ड को कंट्रोल और ऐनिमेट करें

WindowInsetsCompat का इस्तेमाल करके, आपका ऐप्लिकेशन ऑन-स्क्रीन कीबोर्ड (इसे आईएमई भी कहा जाता है) से उसी तरह क्वेरी कर सकता है और उसे कंट्रोल कर सकता है जिस तरह वह सिस्टम बार से इंटरैक्ट करता है. आपका ऐप्लिकेशन, सॉफ़्टवेयर कीबोर्ड के खुलने या बंद होने पर, आसानी से ट्रांज़िशन बनाने के लिए भी 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;
});

सॉफ़्टवेयर कीबोर्ड के साथ ऐनिमेशन सिंक करना

जब कोई उपयोगकर्ता टेक्स्ट इनपुट फ़ील्ड पर टैप करता है, तो कीबोर्ड स्क्रीन के सबसे नीचे से स्लाइड करके अपनी जगह पर आ जाता है. इसका उदाहरण यहां दिया गया है:

दूसरी इमेज. सिंक किया गया कीबोर्ड ऐनिमेशन.
  • दूसरे चित्र में, "अनसिंक्रोनाइज़ किया गया" लेबल वाले उदाहरण में, Android 10 (एपीआई लेवल 29) में डिफ़ॉल्ट व्यवहार दिखाया गया है. इसमें, ऐप्लिकेशन का टेक्स्ट फ़ील्ड और कॉन्टेंट, कीबोर्ड के ऐनिमेशन के साथ सिंक होने के बजाय, अपनी जगह पर स्नैप हो जाता है. यह ऐसा व्यवहार है जो दिखने में खराब लग सकता है.

  • Android 11 (एपीआई लेवल 30) और इसके बाद के वर्शन में, ऐप्लिकेशन के ट्रांज़िशन को स्क्रीन के सबसे नीचे से ऊपर और नीचे की ओर स्लाइड करने वाले कीबोर्ड के साथ सिंक करने के लिए, WindowInsetsAnimationCompat का इस्तेमाल किया जा सकता है. यह सिलसिलेवार तरीके से दिखता है, जैसा कि दूसरी इमेज में "सिंक किया गया" लेबल वाले उदाहरण में दिखाया गया है.

कीबोर्ड ऐनिमेशन के साथ सिंक किए जाने वाले व्यू के साथ, 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() का इस्तेमाल करना.

यहां दिया गया स्निपेट, 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() का इस्तेमाल करना.

यहां दिया गया स्निपेट, 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() का इस्तेमाल करना.

यहां दिया गया स्निपेट, 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 को बदलने का विकल्प भी है. ऐनिमेशन खत्म होने के बाद, इस तरीके को कॉल किया जाता है. यह समय, कुछ समय के लिए किए गए बदलावों को हटाने का अच्छा समय है.

अन्य संसाधन