WindowInsetsCompat ব্যবহার করে,
আপনার অ্যাপ স্ক্রিনের কীবোর্ড (IME নামেও পরিচিত) কোয়েরি ও কন্ট্রোল করতে পারে,
যেভাবে এটি সিস্টেম বারের সাথে ইন্টার্যাক্ট করে। সফ্টওয়্যার কীবোর্ড খোলা বা বন্ধ করার সময় আপনার অ্যাপটি নির্বিঘ্ন ট্রানজিশন তৈরি করতে
WindowInsetsAnimationCompat
ব্যবহার করতে পারে।
পূর্বশর্ত
সফ্টওয়্যার কীবোর্ডের জন্য কন্ট্রোল ও অ্যানিমেশন সেট-আপ করার আগে, আপনার অ্যাপকে এজ-টু-এজ ডিসপ্লে করার জন্য কনফিগার করুন। এটি সিস্টেম বার ও স্ক্রিনের কীবোর্ডের মতো সিস্টেম উইন্ডো ইনসেট ম্যানেজ করতে সাহায্য করে।
ডিফল্ট সিঙ্ক্রোনাইজ করা ইনসেট অ্যানিমেশন
API লেভেল ৩৭.২ এবং তার পরবর্তী ভার্সন থেকে, যেসব অ্যাপ্লিকেশন ডিফল্ট উইন্ডো লেআউট
অ্যাডজাস্টমেন্ট ব্যবহার করে (যেমন, SOFT_INPUT_ADJUST_RESIZE বা SOFT_INPUT_ADJUST_PAN যখন
WindowInsetsController.show(WindowInsets.Type.ime()) ব্যবহার করে IME দেখানো হয়)
কাস্টম WindowInsetsAnimationCompat.Callback প্রয়োগ না করে, সেগুলি সিস্টেম-লেভেল সিঙ্ক করা ফ্রেম-বাই-ফ্রেম অ্যানিমেশন
থেকে সুবিধা পেতে পারে। চালু করা হলে, এই
ফিচারটি প্রতিটি ফ্রেমে অটোমেটিক ইনসেট প্রয়োগ করে এবং একটি লেআউট পাস ট্রিগার করে, কীবোর্ড সরানোর সাথে সাথে একটি মসৃণ ট্রানজিশন তৈরি করে।
এই আচরণ চালু করতে, AndroidManifest.xml ফাইলে আপনার অ্যাক্টিভিটি বা অ্যাপ্লিকেশনে নিম্নলিখিত <property> ট্যাগ যোগ করুন:
<property
android:name="android.window.PROPERTY_COMPAT_ALLOW_SYNCHRONIZED_INSETS_ANIMATION"
android:value="true" />
প্রধান থ্রেড থেকে ইনসেট অ্যানিমেশন পারফর্ম করুন
ডিফল্ট হিসেবে,
WindowInsetsAnimationCompat.Callback রেজিস্টার করলে,
উইন্ডো ইনসেট অ্যানিমেশন অ্যাপের মূল থ্রেডে রান করে। অ্যানিমেশন চলাকালীন (যেমন onProgress পদ্ধতিতে) আপনার অ্যাপ ক্রমাগত আপডেট এবং ভিউ লেআউট সিঙ্ক করলে এটি প্রয়োজন। তবে, আপনার অ্যাপকে যদি
শুধুমাত্র লাইফসাইকেল ট্রানজিশন শুনতে হয় (যেমন, IME অ্যানিমেশন শুরু বা
শেষ হওয়ার সময়) এবং ফ্রেম-বাই-ফ্রেম ভিউ আপডেট করার প্রয়োজন না হয়, তাহলে
প্রধান থ্রেডে রান করলে অপ্রয়োজনীয় ওভারহেড এবং অ্যানিমেশন স্টাটার হতে পারে—বিশেষ করে
প্রধান থ্রেড অন্য কোনও কাজে ব্যস্ত থাকলে।
API লেভেল ৩৭.২ এবং তার থেকে বেশি ভার্সনে, আপনি পরিবর্তে এই ট্রানজিশনগুলি পর্যবেক্ষণ করতে
ViewTreeObserver.WindowInsetsAnimationListener
ব্যবহার করতে পারেন। যেহেতু এই লিসেনার ফ্রেম-বাই-ফ্রেম প্রগ্রেস আপডেট পায় না (কোনও onProgress কলব্যাক নেই), তাই সিস্টেম মূল থ্রেডের পরিবর্তে একটি ডেডিকেটেড অ্যানিমেশন থ্রেডে ইনসেট অ্যানিমেশন চালাতে পারে, যার ফলে আরও মসৃণ ট্রানজিশন হয়।
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)
জাভা
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);
কীবোর্ড সফ্টওয়্যার দৃশ্যমানতা চেক করা
সফ্টওয়্যার কীবোর্ড দেখা যাচ্ছে কিনা তা চেক করতে WindowInsets ব্যবহার করুন।
Kotlin
val insets = ViewCompat.getRootWindowInsets(view) ?: return val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()) val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
জাভা
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 }
জাভা
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; return insets; });
সফ্টওয়্যার কীবোর্ডের সাথে অ্যানিমেশন সিঙ্ক্রোনাইজ করুন
ব্যবহারকারী টেক্সট ইনপুট ফিল্ডে ট্যাপ করলে, স্ক্রিনের নিচের দিক থেকে কীবোর্ড স্লাইড করে উপরে উঠে আসে, যেমনটি নিচের উদাহরণে দেখানো হয়েছে:
ছবি ২-এ "সিঙ্ক করা নেই" লেবেল করা উদাহরণটি Android 10 (API লেভেল ২৯)-এ ডিফল্ট অ্যাকশন দেখায়, যেখানে অ্যাপের টেক্সট ফিল্ড ও কন্টেন্ট কীবোর্ডের অ্যানিমেশনের সাথে সিঙ্ক করার পরিবর্তে নিজেদের জায়গায় স্ন্যাপ করে—এই অ্যাকশনটি দেখতে খারাপ লাগতে পারে।
Android 11 (API লেভেল 30) এবং তার পরবর্তী ভার্সনে, আপনি
WindowInsetsAnimationCompatব্যবহার করে স্ক্রিনের নিচের দিক থেকে কীবোর্ড উপরে ও নিচে স্লাইড করার সাথে অ্যাপের ট্রানজিশন সিঙ্ক করতে পারবেন। এটি আরও মসৃণ দেখায়, যেমনটি চিত্র ২-এ "সিঙ্ক করা" লেবেলযুক্ত উদাহরণে দেখানো হয়েছে।
কীবোর্ড অ্যানিমেশনের সাথে সিঙ্ক করার জন্য ভিউ সহ
WindowInsetsAnimationCompat.Callback
কনফিগার করুন।
Kotlin
ViewCompat.setWindowInsetsAnimationCallback( view, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) { // Override methods. } )
জাভা
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() }
জাভা
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 }
জাভা
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 }
জাভা
@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 ওভাররাইড করতে পারবেন। অ্যানিমেশন শেষ হওয়ার পরে এই পদ্ধতি
কল করা হয়। সাময়িক কোনও পরিবর্তন করা হয়ে থাকলে তা মুছে ফেলার জন্য এটি উপযুক্ত সময়।
অতিরিক্ত রিসোর্স
- GitHub-এ WindowInsetsAnimation ।