שליטה במקלדת התוכנה והנפשה

באמצעות WindowInsetsCompat, האפליקציה יכולה לשלוח שאילתות ולשלוט במקלדת שמופיעה במסך (נקראת גם IME) בדומה ל- הדרך שבה הוא מקיים אינטראקציה עם סרגלי המערכת. האפליקציה שלך יכולה גם להשתמש WindowInsetsAnimationCompat כדי ליצור מעברים חלקים כשמקלדת התוכנה נפתחת או נסגרת.

איור 1. שתי דוגמאות למקלדת התוכנה מעבר סגור.

דרישות מוקדמות

לפני הגדרת הבקרה והאנימציה למקלדת התוכנה, יש להגדיר את האפליקציה להציג מקצה לקצה. כך אפשר הוא מטפל בinsets של חלון המערכת כמו בסרגלי המערכת ובמקלדת שמופיעה במסך.

בדיקת הרשאות הגישה לתוכנה של המקלדת

בדיקת התוכנה באמצעות 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;
});

סנכרון אנימציה עם מקלדת התוכנה

משתמש שמקיש על שדה להזנת טקסט גורמת למקלדת להחליק למקומה בתחתית המסך, כפי שמוצג בדוגמה הבאה:

איור 2. אנימציה של מקלדת מסונכרנת.
  • דוגמה עם התווית 'לא מסונכרן' בתרשים 2 מוצגת התנהגות ברירת המחדל בגרסה Android 10 (רמת API 29), שבה שדה הטקסט והתוכן של האפליקציה במקום לסנכרן אותו עם המקלדת אנימציה - התנהגות שעלולה להיות צרה מבחינה חזותית.

  • ב-Android מגרסה 11 (רמת API 30) ואילך, אפשר להשתמש WindowInsetsAnimationCompat כדי לסנכרן את המעבר של האפליקציה עם שהמקלדת מחליקים למעלה ולמטה מתחתית המסך. זה נראה בצורה חלקה יותר, כמו בדוגמה בשם "מסונכרן" בתרשים 2.

הגדר 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 כשמתחילה אנימציית Inset ולפני הצפיות מנוסחות מחדש בגלל אנימציה. אפשר להשתמש בו כדי לשמור את מצב ההתחלה, שבמקרה הזה הוא הקואורדינטה התחתונה של התצוגה.

תמונה שמראה את הקואורדינטה התחתונה של מצב ההתחלה של תצוגת הרמה הבסיסית.
איור 3. שימוש ב-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 כשמתחילה אנימציית inset. אפשר להשתמש בו כדי להגדיר מאפייני התצוגה למצב הסיום של שינויי הפריסה. אם יש לך הקריאה החוזרת (callback) של OnApplyWindowInsetsListener הוגדרה לאחת מהתצוגות, היא כבר שקוראים לו בשלב הזה. זה זמן טוב לשמור את מצב הסיום של התצוגה נכסים.

תמונה שמראה את הקואורדינטה התחתונה של מצב הסיום
איור 4. הקלטה באמצעות 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 למיקום הפריסה המקורי.

איור 5. שימוש ב-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. השיטה הזו נקראת אחרי האנימציה הסתיים. זהו זמן טוב לנקות את כל השינויים הזמניים.

מקורות מידע נוספים