تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
تجربة طريقة "الكتابة"
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي يُنصح باستخدامها على Android. تعرَّف على كيفية استخدام لوحة المفاتيح في ميزة "الكتابة نيابةً عني".
باستخدام WindowInsetsCompat،
يمكن لتطبيقك طلب معلومات من لوحة المفاتيح على الشاشة والتحكّم فيها (المعروفة أيضًا باسم
IME) بطريقة مشابهة
لطريقة تفاعله مع أشرطة النظام. يمكن لتطبيقك أيضًا استخدام
WindowInsetsAnimationCompat
لإنشاء انتقالات سلسة عند فتح لوحة المفاتيح البرمجية أو إغلاقها.
الشكل 1. مثالان على عملية الانتقال بين فتح وإغلاق لوحة المفاتيح البرمجية
المتطلّبات الأساسية
قبل إعداد عناصر التحكّم والرسوم المتحركة للوحة المفاتيح البرمجية، اضبط تطبيقك على عرض المحتوى من الحافة إلى الحافة. ويتيح ذلك التعامل مع حواف نوافذ النظام، مثل أشرطة النظام ولوحة المفاتيح على الشاشة.
التحقّق من ظهور برنامج لوحة المفاتيح
استخدِم WindowInsets للتحقّق من إمكانية ظهور لوحة المفاتيح على الشاشة.
عندما ينقر المستخدم على حقل إدخال نص، تنزلق لوحة المفاتيح إلى مكانها من أسفل الشاشة، كما هو موضّح في المثال التالي:
الشكل 2. صورة متحركة متزامنة للوحة المفاتيح
يوضّح المثال الذي يحمل التصنيف "غير متزامن" في الشكل 2 السلوك التلقائي في نظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات)، حيث يتم تثبيت حقل النص ومحتوى التطبيق في مكانهما بدلاً من مزامنتهما مع حركة لوحة المفاتيح، وهو سلوك قد يكون مزعجًا بصريًا.
في الإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك استخدام
WindowInsetsAnimationCompat لمزامنة انتقال التطبيق مع
انزلاق لوحة المفاتيح للأعلى والأسفل من أسفل الشاشة. يبدو هذا
أكثر سلاسة، كما هو موضّح في المثال الذي يحمل التصنيف "متزامن" في الشكل 2.
تتوفّر عدة طرق لتجاوز القيم التلقائية في WindowInsetsAnimationCompat.Callback،
وهي
onPrepare()
وonStart()
وonProgress()
وonEnd().
ابدأ باستدعاء onPrepare() قبل إجراء أي تغييرات على التصميم.
يتم استدعاء onPrepare عند بدء حركة إدخال وقبل إعادة تخطيط طرق العرض بسبب الحركة. يمكنك استخدامها لحفظ حالة البدء، وهي في هذه الحالة الإحداثي السفلي للعرض.
يتم استدعاء onStart عند بدء صورة متحركة للعناصر الناشئة. يمكنك استخدامها لضبط جميع خصائص العرض على الحالة النهائية لتغييرات التصميم. إذا كان لديك دالة
OnApplyWindowInsetsListener ردّ تم ضبطها على أي من طرق العرض، سيتم استدعاؤها
في هذه المرحلة. هذا هو الوقت المناسب لحفظ الحالة النهائية لخصائص العرض.
الشكل 4. استخدام onStart() لتسجيل
حالة النهاية
يعرض المقتطف التالي نموذجًا لطلب إلى onStart:
Kotlin
varendBottom=0foverridefunonStart(animation:WindowInsetsAnimationCompat,bounds:WindowInsetsAnimationCompat.BoundsCompat):WindowInsetsAnimationCompat.BoundsCompat{// Record the position of the view after the IME transition.endBottom=view.bottom.toFloat()returnbounds}
يتم استدعاء onProgress عندما تتغير مواضع الإدخال كجزء من تشغيل صورة متحركة،
لذا يمكنك إلغاءها وتلقّي إشعار بشأن كل إطار أثناء
الصورة المتحركة للوحة المفاتيح. عدِّل خصائص طريقة العرض لتتحرّك طريقة العرض بشكل متزامن مع لوحة المفاتيح.
في هذه المرحلة، تكون جميع تغييرات التنسيق قد اكتملت. على سبيل المثال، إذا كنت تستخدم
View.translationY لنقل طريقة العرض، تنخفض القيمة تدريجيًا مع كل
استدعاء لهذه الطريقة، وتصل في النهاية إلى 0 في موضع التصميم الأصلي.
الشكل 5. استخدِم onProgress() لمزامنة الصور المتحركة.
يعرض المقتطف التالي نموذجًا لطلب إلى onProgress:
Kotlin
overridefunonProgress(insets:WindowInsetsCompat,runningAnimations:MutableList<WindowInsetsAnimationCompat>):WindowInsetsCompat{// Find an IME animation.valimeAnimation=runningAnimations.find{it.typeMaskandWindowInsetsCompat.Type.ime()!=0}?:returninsets// Offset the view based on the interpolated fraction of the IME animation.view.translationY=(startBottom-endBottom)*(1-imeAnimation.interpolatedFraction)returninsets}
Java
@NonNull@OverridepublicWindowInsetsCompatonProgress(@NonNullWindowInsetsCompatinsets,@NonNullList<WindowInsetsAnimationCompat>runningAnimations){// Find an IME animation.WindowInsetsAnimationCompatimeAnimation=null;for(WindowInsetsAnimationCompatanimation: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()));}returninsets;}
يمكنك اختياريًا إلغاء onEnd. يتم استدعاء هذه الطريقة بعد انتهاء الصورة المتحركة. هذا هو الوقت المناسب لإزالة أي تغييرات مؤقتة.
يخضع كل من المحتوى وعيّنات التعليمات البرمجية في هذه الصفحة للتراخيص الموضحّة في ترخيص استخدام المحتوى. إنّ Java وOpenJDK هما علامتان تجاريتان مسجَّلتان لشركة Oracle و/أو الشركات التابعة لها.
تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],null,["# Control and animate the software keyboard\n\nTry the Compose way \nJetpack Compose is the recommended UI toolkit for Android. Learn how to work with the keyboard in Compose. \n[Software keyboard in Compose →](/develop/ui/compose/system/keyboard-animations) \n\n\u003cbr /\u003e\n\nUsing [`WindowInsetsCompat`](/reference/androidx/core/view/WindowInsetsCompat),\nyour app can query and control the on-screen keyboard (also called the\n[IME](https://en.wikipedia.org/wiki/Input_method)) similar to the\nway it interacts with the system bars. Your app can also use\n[`WindowInsetsAnimationCompat`](/reference/androidx/core/view/WindowInsetsAnimationCompat)\nto create seamless transitions when the software keyboard is opened or closed.\n**Figure 1.** Two examples of the software keyboard open-closed transition.\n\nPrerequisites\n-------------\n\nBefore setting up control and animation for the software keyboard, configure\nyour app to [display edge-to-edge](/training/gestures/edge-to-edge). This lets\nit handle [system window insets](/develop/ui/views/layout/insets) such as the\nsystem bars and the on-screen keyboard.\n\nCheck keyboard software visibility\n----------------------------------\n\nUse [`WindowInsets`](/reference/android/view/WindowInsets) to check the software\nkeyboard visibility. \n\n### Kotlin\n\n```kotlin\nval insets = ViewCompat.getRootWindowInsets(view) ?: return\nval imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())\nval imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom\n```\n\n### Java\n\n```java\nWindowInsetsCompat insets = ViewCompat.getRootWindowInsets(view);\nboolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime());\nint imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;\n```\n\nAlternatively, you can use\n[`ViewCompat.setOnApplyWindowInsetsListener`](/reference/androidx/core/view/ViewCompat#setOnApplyWindowInsetsListener(android.view.View,%20androidx.core.view.OnApplyWindowInsetsListener))\nto observe changes to software keyboard visibility. \n\n### Kotlin\n\n```kotlin\nViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -\u003e\n val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())\n val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom\n insets\n}\n```\n\n### Java\n\n```java\nViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -\u003e {\n boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime());\n int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;\n return insets;\n});\n```\n| **Note:** To achieve the best backward compatibility with this AndroidX implementation, set `android:windowSoftInputMode=\"adjustResize\"` to the activity in your `AndroidManifest.xml` file.\n\nSynchronize animation with the software keyboard\n------------------------------------------------\n\nA user tapping a text input field causes the keyboard to slide into place from\nthe bottom of the screen, as shown in the following example:\n**Figure 2.** Synchronized keyboard animation.\n\n- The example labeled \"Unsynchronized\" in figure 2 shows the default behavior\n in Android 10 (API level 29), in which the text field and content of the app\n snap into place instead of synchronizing with the keyboard's\n animation---behavior that can be visually jarring.\n\n- In Android 11 (API level 30) and higher, you can use\n `WindowInsetsAnimationCompat` to synchronize the transition of the app with\n the keyboard sliding up and down from the bottom of the screen. This looks\n smoother, as shown in the example labeled \"Synchronized\" in figure 2.\n\n| **Note:** Don't consume `WindowInsets` in `setWindowInsetsApplyListener` for any parent [`ViewGroup`](/reference/android/view/ViewGroup) objects. Instead, let `WindowInsetsAnimatorCompat` handle them on Android 10 and lower.\n\nConfigure\n[`WindowInsetsAnimationCompat.Callback`](/reference/androidx/core/view/WindowInsetsAnimationCompat.Callback)\nwith the view to be synchronized with the keyboard animation. \n\n### Kotlin\n\n```kotlin\nViewCompat.setWindowInsetsAnimationCallback(\n view,\n object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {\n // Override methods.\n }\n)\n```\n\n### Java\n\n```java\nViewCompat.setWindowInsetsAnimationCallback(\n view,\n new WindowInsetsAnimationCompat.Callback(\n WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP\n ) {\n // Override methods.\n });\n```\n\nThere are several methods to override in `WindowInsetsAnimationCompat.Callback`,\nnamely\n[`onPrepare()`](/reference/androidx/core/view/WindowInsetsAnimationCompat.Callback#onPrepare(androidx.core.view.WindowInsetsAnimationCompat)),\n[`onStart()`](/reference/androidx/core/view/WindowInsetsAnimationCompat.Callback#onStart(androidx.core.view.WindowInsetsAnimationCompat,%20androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat)),\n[`onProgress()`](/reference/androidx/core/view/WindowInsetsAnimationCompat.Callback#onProgress(androidx.core.view.WindowInsetsCompat,%20java.util.List%3Candroidx.core.view.WindowInsetsAnimationCompat%3E)),\nand\n[`onEnd()`](/reference/androidx/core/view/WindowInsetsAnimationCompat.Callback#onEnd(androidx.core.view.WindowInsetsAnimationCompat)).\nStart with calling `onPrepare()` before any of the layout changes.\n\n`onPrepare` is called when an insets animation is starting and before the views\nare re-laid out due to an animation. You can use it to save the start state,\nwhich in this case is the bottom coordinate of the view.\n**Figure 3.** Using `onPrepare()` to record the start state.\n\nThe following snippet shows a sample call to `onPrepare`: \n\n### Kotlin\n\n```kotlin\nvar startBottom = 0f\n\noverride fun onPrepare(\n animation: WindowInsetsAnimationCompat\n) {\n startBottom = view.bottom.toFloat()\n}\n```\n\n### Java\n\n```java\nfloat startBottom;\n\n@Override\npublic void onPrepare(\n @NonNull WindowInsetsAnimationCompat animation\n) {\n startBottom = view.getBottom();\n}\n```\n\n`onStart` is called when an insets animation starts. You can use it to set all\nthe view properties to the end state of the layout changes. If you have an\n`OnApplyWindowInsetsListener` callback set to any of the views, it is already\ncalled at this point. This is a good time to save the end state of the view\nproperties.\n**Figure 4.** Using `onStart()` to record the end state.\n\nThe following snippet shows a sample call to `onStart`: \n\n### Kotlin\n\n```kotlin\nvar endBottom = 0f\n\noverride fun onStart(\n animation: WindowInsetsAnimationCompat,\n bounds: WindowInsetsAnimationCompat.BoundsCompat\n): WindowInsetsAnimationCompat.BoundsCompat {\n // Record the position of the view after the IME transition.\n endBottom = view.bottom.toFloat()\n\n return bounds\n}\n```\n\n### Java\n\n```java\nfloat endBottom;\n\n@NonNull\n@Override\npublic WindowInsetsAnimationCompat.BoundsCompat onStart(\n @NonNull WindowInsetsAnimationCompat animation,\n @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds\n) {\n endBottom = view.getBottom();\n return bounds;\n}\n```\n\n`onProgress` is called when the insets change as part of running an animation,\nso you can override it and be notified on every frame during the keyboard\nanimation. Update the view properties so that the view animates in\nsynchronization with the keyboard.\n\nAll the layout changes are complete at this point. For example, if you use\n`View.translationY` to shift the view, the value gradually decreases for every\ncall of this method and eventually reaches `0` to the original layout position.\n**Figure 5.** Using `onProgress()` to synchronize the animations.\n\nThe following snippet shows a sample call to `onProgress`: \n\n### Kotlin\n\n```kotlin\noverride fun onProgress(\n insets: WindowInsetsCompat,\n runningAnimations: MutableList\u003cWindowInsetsAnimationCompat\u003e\n): WindowInsetsCompat {\n // Find an IME animation.\n val imeAnimation = runningAnimations.find {\n it.typeMask and WindowInsetsCompat.Type.ime() != 0\n } ?: return insets\n\n // Offset the view based on the interpolated fraction of the IME animation.\n view.translationY =\n (startBottom - endBottom) * (1 - imeAnimation.interpolatedFraction)\n\n return insets\n}\n```\n\n### Java\n\n```java\n@NonNull\n@Override\npublic WindowInsetsCompat onProgress(\n @NonNull WindowInsetsCompat insets,\n @NonNull List\u003cWindowInsetsAnimationCompat\u003e runningAnimations\n) {\n // Find an IME animation.\n WindowInsetsAnimationCompat imeAnimation = null;\n for (WindowInsetsAnimationCompat animation : runningAnimations) {\n if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) {\n imeAnimation = animation;\n break;\n }\n }\n if (imeAnimation != null) {\n // Offset the view based on the interpolated fraction of the IME animation.\n view.setTranslationY((startBottom - endBottom)\n\n * (1 - imeAnimation.getInterpolatedFraction()));\n }\n return insets;\n}\n```\n\nOptionally, you can override `onEnd`. This method is called after the animation\nis over. This is a good time to clean up any temporary changes.\n\nAdditional resources\n--------------------\n\n- [WindowInsetsAnimation](https://github.com/android/user-interface-samples/tree/main/WindowInsetsAnimation) on GitHub."]]