অঙ্গভঙ্গি নেভিগেশন এবং প্রান্ত থেকে প্রান্ত অভিজ্ঞতা

১. ভূমিকা

অ্যান্ড্রয়েড ভার্সন ১০ বা তার উচ্চতর সংস্করণে, নেভিগেশন জেসচার একটি নতুন মোড হিসেবে সমর্থিত হয়েছে। এটি আপনার অ্যাপকে পুরো স্ক্রিন ব্যবহার করতে এবং আরও আকর্ষণীয় ডিসপ্লে অভিজ্ঞতা প্রদান করতে সাহায্য করে। যখন ব্যবহারকারী স্ক্রিনের নিচের প্রান্ত থেকে উপরের দিকে সোয়াইপ করেন, তখন এটি তাকে অ্যান্ড্রয়েড হোম স্ক্রিনে নিয়ে যায়। যখন তারা বাম বা ডান প্রান্ত থেকে ভেতরের দিকে সোয়াইপ করেন, তখন এটি ব্যবহারকারীকে আগের স্ক্রিনে নিয়ে যায়।

এই দুটি জেসচারের মাধ্যমে আপনার অ্যাপ স্ক্রিনের নিচের অংশের জায়গা ব্যবহার করতে পারে। তবে, যদি আপনার অ্যাপ সিস্টেম জেসচার এলাকায় জেসচার বা কন্ট্রোল ব্যবহার করে, তাহলে এটি সিস্টেম-ব্যাপী জেসচারগুলোর সাথে সংঘাত তৈরি করতে পারে।

এই কোডল্যাবটির উদ্দেশ্য হলো জেসচার কনফ্লিক্ট এড়ানোর জন্য ইনসেট ব্যবহারের পদ্ধতি শেখানো। এছাড়াও, ড্র্যাগ হ্যান্ডেলের মতো যেসব কন্ট্রোলকে জেসচার জোনের মধ্যে থাকতে হয়, তাদের জন্য জেসচার এক্সক্লুশন এপিআই (Gesture Exclusion API) কীভাবে ব্যবহার করতে হয়, তা এই কোডল্যাবটির লক্ষ্য।

আপনি যা শিখবেন

  • ভিউতে ইনসেট লিসেনার কীভাবে ব্যবহার করবেন
  • জেসচার এক্সক্লুশন এপিআই কীভাবে ব্যবহার করবেন
  • জেসচার সক্রিয় থাকাকালীন ইমারসিভ মোড কীভাবে কাজ করে

এই কোডল্যাবটির লক্ষ্য হলো আপনার অ্যাপকে সিস্টেম জেসচারের সাথে সামঞ্জস্যপূর্ণ করে তোলা। অপ্রাসঙ্গিক ধারণা এবং কোড ব্লকগুলো সংক্ষেপে আলোচনা করা হয়েছে এবং আপনার কপি-পেস্ট করার জন্য সেগুলো সরবরাহ করা হয়েছে।

আপনি যা তৈরি করবেন

ইউনিভার্সাল অ্যান্ড্রয়েড মিউজিক প্লেয়ার (UAMP) হলো কোটলিনে লেখা অ্যান্ড্রয়েডের জন্য একটি উদাহরণ মিউজিক প্লেয়ার অ্যাপ। আপনি জেসচারাল নেভিগেশনের জন্য UAMP সেট আপ করবেন।

  • জেসচার এরিয়া থেকে কন্ট্রোলগুলো দূরে সরাতে ইনসেট ব্যবহার করুন।
  • সাংঘর্ষিক কন্ট্রোলগুলোর জন্য ব্যাক জেসচারটি বাদ দিতে জেসচার এক্সক্লুশন এপিআই ব্যবহার করুন।
  • আপনার বিল্ডগুলো ব্যবহার করে জেসচার নেভিগেশনের সাহায্যে ইমারসিভ মোডের আচরণগত পরিবর্তনগুলো অন্বেষণ করুন।

আপনার যা যা লাগবে

২. অ্যাপের সংক্ষিপ্ত বিবরণ

ইউনিভার্সাল অ্যান্ড্রয়েড মিউজিক প্লেয়ার (UAMP) হলো কোটলিনে লেখা অ্যান্ড্রয়েডের জন্য একটি নমুনা মিউজিক প্লেয়ার অ্যাপ। এটি ব্যাকগ্রাউন্ড প্লেব্যাক, অডিও ফোকাস হ্যান্ডলিং, অ্যাসিস্ট্যান্ট ইন্টিগ্রেশন এবং ওয়্যার, টিভি ও অটো-র মতো একাধিক প্ল্যাটফর্মসহ বিভিন্ন ফিচার সমর্থন করে।

চিত্র ১ : ইউএএমপি-তে একটি প্রবাহ

UAMP একটি রিমোট সার্ভার থেকে মিউজিক ক্যাটালগ লোড করে এবং ব্যবহারকারীকে অ্যালবাম ও গান ব্রাউজ করার সুযোগ দেয়। ব্যবহারকারী কোনো গানের উপর ট্যাপ করলে, সেটি সংযুক্ত স্পিকার বা হেডফোনের মাধ্যমে বাজতে শুরু করে। অ্যাপটি সিস্টেম জেসচারের সাথে কাজ করার জন্য ডিজাইন করা হয়নি। তাই, যখন আপনি অ্যান্ড্রয়েড ১০ বা তার উচ্চতর সংস্করণের কোনো ডিভাইসে UAMP চালান, তখন প্রাথমিকভাবে কিছু সমস্যার সম্মুখীন হতে পারেন।

৩. প্রস্তুত হন

স্যাম্পল অ্যাপটি পেতে, গিটহাব থেকে রিপোজিটরিটি ক্লোন করুন এবং স্টার্টার ব্রাঞ্চে যান:

$  git clone https://github.com/googlecodelabs/android-gestural-navigation/

বিকল্পভাবে, আপনি রিপোজিটরিটি একটি জিপ ফাইল হিসেবে ডাউনলোড করে, সেটিকে আনজিপ করে অ্যান্ড্রয়েড স্টুডিওতে খুলতে পারেন।

নিম্নলিখিত ধাপগুলি সম্পূর্ণ করুন:

  1. অ্যান্ড্রয়েড স্টুডিওতে অ্যাপটি খুলুন এবং বিল্ড করুন।
  2. একটি নতুন ভার্চুয়াল ডিভাইস তৈরি করুন এবং এপিআই লেভেল ২৯ নির্বাচন করুন। বিকল্পভাবে, আপনি এপিআই লেভেল ২৯ বা তার চেয়ে উচ্চতর সংস্করণে চালিত একটি আসল ডিভাইস সংযোগ করতে পারেন।
  3. অ্যাপটি চালান। আপনি যে তালিকাটি দেখবেন, তাতে গানগুলো ‘প্রস্তাবিত ’ এবং ‘অ্যালবাম’ এই দুটি ভাগে বিভক্ত করা আছে।
  4. রেকমেন্ডেড-এ ক্লিক করুন এবং গানের তালিকা থেকে একটি গান বেছে নিন।
  5. অ্যাপটি গানটি বাজানো শুরু করে।

অঙ্গভঙ্গি নেভিগেশন সক্ষম করুন

আপনি যদি এপিআই লেভেল ২৯ সহ একটি নতুন এমুলেটর ইনস্ট্যান্স চালান, তাহলে জেসচার নেভিগেশন ডিফল্টরূপে চালু নাও থাকতে পারে। জেসচার নেভিগেশন সক্রিয় করতে, সিস্টেম সেটিংস > সিস্টেম > সিস্টেম নেভিগেশন > জেসচার নেভিগেশন নির্বাচন করুন।

জেসচার নেভিগেশন ব্যবহার করে অ্যাপটি চালান

আপনি যদি জেসচার নেভিগেশন চালু রেখে অ্যাপটি চালান এবং কোনো গান বাজানো শুরু করেন, তাহলে আপনি হয়তো লক্ষ্য করবেন যে প্লেয়ারের কন্ট্রোলগুলো হোম এবং ব্যাক জেসচার এলাকার খুব কাছাকাছি রয়েছে।

৪. এক প্রান্ত থেকে অন্য প্রান্তে যান

এজ-টু-এজ বলতে কী বোঝায়?

অ্যান্ড্রয়েড ১০ বা তার উচ্চতর সংস্করণে চালিত অ্যাপগুলো, নেভিগেশনের জন্য জেসচার বা বাটন চালু থাকুক বা না থাকুক, একটি সম্পূর্ণ এজ-টু-এজ স্ক্রিন অভিজ্ঞতা দিতে পারে। এজ-টু-এজ অভিজ্ঞতা দেওয়ার জন্য, আপনার অ্যাপগুলোকে অবশ্যই স্বচ্ছ নেভিগেশন এবং স্ট্যাটাস বারের পিছনে ড্র করতে হবে।

নেভিগেশন বারের পিছনে আঁকুন

আপনার অ্যাপে নেভিগেশন বারের নিচে কন্টেন্ট রেন্ডার করার জন্য, আপনাকে প্রথমে নেভিগেশন বারের ব্যাকগ্রাউন্ড স্বচ্ছ করতে হবে। এরপর আপনাকে স্ট্যাটাস বারটিও স্বচ্ছ করতে হবে। এর ফলে আপনার অ্যাপটি স্ক্রিনের সম্পূর্ণ উচ্চতা জুড়ে প্রদর্শিত হতে পারবে।

ন্যাভিগেশন বার এবং স্ট্যাটাস বারের রঙ পরিবর্তন করতে, নিম্নলিখিত ধাপগুলো অনুসরণ করুন:

  1. নেভিগেশন বার: res/values-29/styles.xml খুলুন এবং navigationBarColor color/transparent এ সেট করুন।
  2. স্ট্যাটাস বার: একইভাবে statusBarColor color/transparent এ সেট করুন।

res/values-29/styles.xml ফাইলের নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

<!-- change navigation bar color -->
<item name="android:navigationBarColor">
    @android:color/transparent
</item>

<!-- change status bar color -->
<item name="android:statusBarColor">
    @android:color/transparent
</item>

সিস্টেম UI দৃশ্যমানতা ফ্ল্যাগ

সিস্টেম বারগুলির নীচে অ্যাপটিকে লেআউট করার জন্য আপনাকে অবশ্যই সিস্টেম UI ভিজিবিলিটি ফ্ল্যাগগুলি সেট করতে হবে। View ক্লাসের systemUiVisibility API ব্যবহার করে বিভিন্ন ধরণের ফ্ল্যাগ সেট করা যায়। নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. MainActivity.kt ক্লাসটি খুলুন এবং onCreate() মেথডটি খুঁজুন। fragmentContainer এর একটি ইনস্ট্যান্স নিন।
  2. content.systemUiVisibility তে নিম্নলিখিতটি সেট করুন:

MainActivity.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

  val content: FrameLayout = findViewById(R.id.fragmentContainer)
  content.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

যখন আপনি এই ফ্ল্যাগগুলো একসাথে সেট করেন, তখন আপনি সিস্টেমকে জানিয়ে দেন যে আপনি আপনার অ্যাপটিকে ফুলস্ক্রিনে প্রদর্শন করতে চান, যেন নেভিগেশন এবং স্ট্যাটাস বারগুলো সেখানে নেই। নিম্নলিখিত ধাপগুলো অনুসরণ করুন:

  1. অ্যাপটি চালু করুন এবং প্লেয়ার স্ক্রিনে যাওয়ার জন্য, চালানোর জন্য একটি গান নির্বাচন করুন।
  2. যাচাই করুন যে প্লেয়ার কন্ট্রোলগুলো নেভিগেশন বারের নিচে আঁকা হয়েছে, যার ফলে সেগুলো অ্যাক্সেস করা কঠিন হয়ে পড়ে:

  1. সিস্টেম সেটিংসে যান, তিন-বোতাম নেভিগেশন মোডে ফিরে যান এবং অ্যাপে ফিরে আসুন।
  2. লক্ষ্য করুন যে তিনটি বাটনের নেভিগেশন বারের সাথে কন্ট্রোলগুলো ব্যবহার করা আরও কঠিন: খেয়াল করুন যে SeekBar নেভিগেশন বারের পিছনে লুকানো থাকে এবং প্লে/পজ (Play/Pause) বাটনটি বেশিরভাগই নেভিগেশন বার দ্বারা ঢাকা থাকে।
  3. কিছুটা অন্বেষণ ও পরীক্ষা-নিরীক্ষা করুন। আপনার কাজ শেষ হলে, সিস্টেম সেটিংসে যান এবং জেসচার নেভিগেশনে ফিরে যান:

741ef664e9be5e7f.gif

অ্যাপটি এখন প্রান্ত থেকে প্রান্ত পর্যন্ত প্রদর্শিত হচ্ছে, কিন্তু এতে ব্যবহারযোগ্যতার সমস্যা রয়েছে, যেমন অ্যাপের কন্ট্রোলগুলোর মধ্যে সংঘাত ও ওভারল্যাপ হচ্ছে, এবং এগুলোর সমাধান করা আবশ্যক।

৫. ইনসেট

WindowInsets অ্যাপকে বলে দেয় যে আপনার কন্টেন্টের উপরে সিস্টেম UI কোথায় প্রদর্শিত হবে, এবং স্ক্রিনের কোন কোন অঞ্চলে ইন-অ্যাপ জেসচারের চেয়ে সিস্টেম জেসচার অগ্রাধিকার পাবে। Jetpack-WindowInsets ক্লাস এবং WindowInsetsCompat ক্লাসের মাধ্যমে ইনসেটগুলোকে উপস্থাপন করা হয়। সমস্ত API লেভেলে সামঞ্জস্যপূর্ণ আচরণ নিশ্চিত করতে আমরা আপনাকে WindowInsetsCompat ব্যবহার করার জন্য দৃঢ়ভাবে সুপারিশ করি।

সিস্টেম ইনসেট এবং বাধ্যতামূলক সিস্টেম ইনসেট

নিম্নলিখিত ইনসেট এপিআইগুলো হলো সর্বাধিক ব্যবহৃত ইনসেট টাইপগুলো:

  • সিস্টেম উইন্ডো ইনসেট: এগুলি আপনাকে বলে দেয় যে সিস্টেম UI আপনার অ্যাপের উপরে কোথায় প্রদর্শিত হবে। আমরা আলোচনা করব কীভাবে আপনি সিস্টেম ইনসেট ব্যবহার করে আপনার কন্ট্রোলগুলিকে সিস্টেম বার থেকে দূরে সরিয়ে নিতে পারেন।
  • সিস্টেম জেসচার ইনসেট: এগুলি সমস্ত জেসচার এলাকা ফিরিয়ে আনে। এই অঞ্চলগুলিতে থাকা যেকোনো ইন-অ্যাপ সোয়াইপ কন্ট্রোল ভুলবশত সিস্টেম জেসচার চালু করে দিতে পারে।
  • বাধ্যতামূলক জেসচার ইনসেট: এগুলি সিস্টেম জেসচার ইনসেটগুলির একটি উপসেট এবং এগুলিকে ওভাররাইড করা যায় না। এগুলি আপনাকে স্ক্রিনের সেই এলাকাগুলি সম্পর্কে জানায় যেখানে ইন-অ্যাপ জেসচারের চেয়ে সিস্টেম জেসচারের আচরণ সর্বদা অগ্রাধিকার পাবে।

অ্যাপ কন্ট্রোলগুলি সরাতে ইনসেট ব্যবহার করুন

এখন যেহেতু আপনি ইনসেট এপিআই (inset APIs) সম্পর্কে আরও জানেন, আপনি নিম্নলিখিত ধাপগুলিতে বর্ণিত পদ্ধতি অনুযায়ী অ্যাপ কন্ট্রোলগুলি ঠিক করতে পারেন:

  1. view অবজেক্ট ইনস্ট্যান্স থেকে playerLayout এর একটি ইনস্ট্যান্স নিন।
  2. playerView তে একটি OnApplyWindowInsetsListener যোগ করুন।
  3. ভিউটিকে জেসচার এরিয়া থেকে দূরে সরান: বটম-এর জন্য সিস্টেম ইনসেট ভ্যালুটি খুঁজুন এবং সেই পরিমাণ দ্বারা ভিউটির প্যাডিং বাড়িয়ে দিন। সেই অনুযায়ী ভিউটির প্যাডিং আপডেট করতে, [অ্যাপের বটম প্যাডিং-এর সাথে যুক্ত ভ্যালু]-এর সাথে [সিস্টেমের ইনসেট বটম ভ্যালু-এর সাথে যুক্ত ভ্যালুটি] যোগ করুন।

NowPlayingFragment.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
   view.updatePadding(
      bottom = insets.systemWindowInsetBottom + view.paddingBottom
   )
   insets
}
  1. অ্যাপটি চালান এবং একটি গান নির্বাচন করুন। লক্ষ্য করুন যে প্লেয়ার কন্ট্রোলগুলিতে কোনো পরিবর্তন হচ্ছে না। যদি আপনি একটি ব্রেকপয়েন্ট যোগ করে অ্যাপটি ডিবাগ মোডে চালান, তাহলে দেখতে পাবেন যে লিসেনারটি কল করা হচ্ছে না।
  2. এটি সমাধান করতে, FragmentContainerView ব্যবহার করুন, যা এই সমস্যাটি স্বয়ংক্রিয়ভাবে সমাধান করে। activity_main.xml খুলুন এবং FrameLayout FragmentContainerView তে পরিবর্তন করুন।

activity_main.xml এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragmentContainer"
    tools:context="com.example.android.uamp.MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  1. অ্যাপটি আবার চালান এবং প্লেয়ার স্ক্রিনে যান। প্লেয়ারের নিচের কন্ট্রোলগুলো নিচের জেসচার এরিয়া থেকে সরে গেছে।

অ্যাপের কন্ট্রোলগুলো এখন জেসচার নেভিগেশনের সাথে কাজ করছে, কিন্তু কন্ট্রোলগুলো প্রত্যাশার চেয়ে বেশি নড়াচড়া করছে। আপনাকে অবশ্যই এর সমাধান করতে হবে।

বর্তমান প্যাডিং এবং মার্জিন বজায় রাখুন

অ্যাপটি বন্ধ না করে যদি আপনি অন্য অ্যাপে যান বা হোম স্ক্রিনে গিয়ে আবার অ্যাপটিতে ফিরে আসেন, তাহলে খেয়াল করবেন যে প্রতিবার প্লেয়ার কন্ট্রোলগুলো উপরে উঠে যায়।

এর কারণ হলো, প্রতিবার অ্যাক্টিভিটি শুরু হওয়ার সময় অ্যাপটি requestApplyInsets() কলটি ট্রিগার করে। এই কলটি ছাড়াও, একটি ভিউ-এর লাইফসাইকেলের যেকোনো সময়ে WindowInsets একাধিকবার ডিসপ্যাচ করা যেতে পারে।

playerView এর বর্তমান InsetListener প্রথমবার নিখুঁতভাবে কাজ করে, যখন আপনি activity_main.xml এ ঘোষিত অ্যাপের bottom padding মানের সমান inset bottom মান যোগ করেন। কিন্তু, পরবর্তী কলগুলোতে inset bottom মানটি ইতিমধ্যেই আপডেট করা ভিউটির bottom padding-এর সাথে যোগ হতে থাকে।

এর প্রতিকার করতে, নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করুন:

  1. প্রাথমিক ভিউ প্যাডিং মানটি রেকর্ড করুন। একটি নতুন `val` তৈরি করুন এবং লিসেনার কোডের ঠিক আগে playerView এর প্রাথমিক ভিউ প্যাডিং মানটি সেখানে সংরক্ষণ করুন।

NowPlayingFragment.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

   val initialPadding = playerView.paddingBottom
  1. ভিউ-এর বটম প্যাডিং আপডেট করতে এই প্রাথমিক মানটি ব্যবহার করুন, যা আপনাকে অ্যাপের বর্তমান বটম প্যাডিং মান ব্যবহার করা এড়াতে সাহায্য করে।

NowPlayingFragment.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

   playerView.setOnApplyWindowInsetsListener { view, insets ->
            view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
            insets
        }
  1. অ্যাপটি আবার চালান। অ্যাপগুলোর মধ্যে নেভিগেট করে হোম স্ক্রিনে যান। আপনি যখন অ্যাপটিতে ফিরে আসবেন, তখন প্লেয়ার কন্ট্রোলগুলো জেসচার এরিয়ার ঠিক উপরেই থাকবে।

অ্যাপ নিয়ন্ত্রণগুলি পুনরায় ডিজাইন করুন

প্লেয়ারের সিকবারটি নিচের জেসচার এরিয়ার খুব কাছে রয়েছে, যার ফলে ব্যবহারকারী হরাইজন্টাল সোয়াইপ করার সময় ভুলবশত হোম জেসচারটি চালু করে ফেলতে পারেন। প্যাডিং আরও বাড়ালে সমস্যাটির সমাধান হতে পারে, কিন্তু এতে প্লেয়ারটি প্রয়োজনের চেয়ে বেশি উপরে উঠে যেতে পারে।

ইনসেট ব্যবহার করে জেসচার কনফ্লিক্ট সমাধান করা যায়, কিন্তু কখনও কখনও ছোটখাটো ডিজাইন পরিবর্তনের মাধ্যমে জেসচার কনফ্লিক্ট পুরোপুরি এড়ানো সম্ভব। জেসচার কনফ্লিক্ট এড়ানোর জন্য প্লেয়ার কন্ট্রোলগুলো পুনরায় ডিজাইন করতে, নিম্নলিখিত ধাপগুলো অনুসরণ করুন:

  1. fragment_nowplaying.xml খুলুন। ডিজাইন ভিউতে যান এবং একদম নিচের SeekBar টি সিলেক্ট করুন:

74918dec3926293f.png

  1. কোড ভিউতে যান।
  2. SeekBar playerLayout এর শীর্ষে সরাতে, SeekBar-এর layout_constraintTop_toBottomOf কে parent এ পরিবর্তন করুন।
  3. playerView এর অন্যান্য আইটেমগুলোকে SeekBar এর নিচে সীমাবদ্ধ করতে, media_button , title , এবং position এর layout_constraintTop_toTopOf parent থেকে @+id/seekBar এ পরিবর্তন করুন।

fragment_nowplaying.xml এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

<androidx.constraintlayout.widget.ConstraintLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:padding="8dp"
   android:layout_gravity="bottom"
   android:background="@drawable/media_overlay_background"
   android:id="@+id/playerLayout">

   <ImageButton
       android:id="@+id/media_button"
       android:layout_width="@dimen/exo_media_button_width"
       android:layout_height="@dimen/exo_media_button_height"
       android:background="?attr/selectableItemBackground"
       android:scaleType="centerInside"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:srcCompat="@drawable/ic_play_arrow_black_24dp"
       tools:ignore="ContentDescription" />

   <TextView
       android:id="@+id/title"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Song Title" />

   <TextView
       android:id="@+id/subtitle"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@+id/title"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Artist" />

   <TextView
       android:id="@+id/position"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <TextView
       android:id="@+id/duration"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@id/position"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <SeekBar
       android:id="@+id/seekBar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. অ্যাপটি চালান এবং প্লেয়ার ও সিকবারটি ব্যবহার করুন।

এই সামান্য ডিজাইন পরিবর্তনগুলো অ্যাপটিকে উল্লেখযোগ্যভাবে উন্নত করে।

৬. জেসচার এক্সক্লুশন এপিআই

হোম জেসচার এলাকায় জেসচার দ্বন্দ্বের জন্য প্লেয়ার কন্ট্রোলগুলো ঠিক করা হয়েছে। ব্যাক জেসচার এলাকাও অ্যাপ কন্ট্রোলের সাথে দ্বন্দ্ব তৈরি করতে পারে। নিম্নলিখিত স্ক্রিনশটটি দেখাচ্ছে যে প্লেয়ারের সিকবারটি বর্তমানে ডান এবং বাম উভয় ব্যাক জেসচার এলাকাতেই অবস্থান করছে:

e6d98e94dcf83dde.png

SeekBar স্বয়ংক্রিয়ভাবে জেসচার কনফ্লিক্ট সামলে নেয়। তবুও আপনার এমন অন্যান্য UI কম্পোনেন্ট ব্যবহার করার প্রয়োজন হতে পারে যা জেসচার কনফ্লিক্ট তৈরি করে। এইসব ক্ষেত্রে, আপনি ব্যাক জেসচারটি আংশিকভাবে এড়িয়ে যাওয়ার জন্য Gesture Exclusion API ব্যবহার করতে পারেন।

জেসচার এক্সক্লুশন এপিআই ব্যবহার করুন

একটি জেসচার এক্সক্লুশন জোন তৈরি করতে, আপনার ভিউতে rect অবজেক্টের একটি তালিকা সহ setSystemGestureExclusionRects() কল করুন। এই rect অবজেক্টগুলো বাদ দেওয়া আয়তক্ষেত্রাকার এলাকাগুলোর স্থানাঙ্কের সাথে ম্যাপ করা থাকে। এই কলটি অবশ্যই ভিউয়ের onLayout() বা onDraw() মেথডের মধ্যে করতে হবে। এটি করার জন্য, নিম্নলিখিত ধাপগুলো অনুসরণ করুন:

  1. view নামে একটি নতুন প্যাকেজ তৈরি করুন।
  2. এই API-টি কল করার জন্য, MySeekBar নামে একটি নতুন ক্লাস তৈরি করুন এবং AppCompatSeekBar এক্সটেন্ড করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

class MySeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = android.R.attr.seekBarStyle
) : androidx.appcompat.widget.AppCompatSeekBar(context, attrs, defStyle) {

}
  1. updateGestureExclusion() নামে একটি নতুন মেথড তৈরি করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

private fun updateGestureExclusion() {

}
  1. এপিআই লেভেল ২৮ বা তার নিচের সংস্করণে এই কলটি এড়িয়ে যাওয়ার জন্য একটি চেক যুক্ত করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

private fun updateGestureExclusion() {
        // Skip this call if we're not running on Android 10+
        if (Build.VERSION.SDK_INT < 29) return
}
  1. যেহেতু জেসচার এক্সক্লুশন এপিআই-এর ২০০ ডিপি-এর একটি সীমা রয়েছে, তাই শুধুমাত্র সিকবারের থাম্বটি বাদ দিন। সিকবারের বাউন্ডস-এর একটি কপি নিন এবং প্রতিটি অবজেক্টকে একটি পরিবর্তনযোগ্য তালিকায় যুক্ত করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
}
  1. আপনার তৈরি করা gestureExclusionRects তালিকাগুলো দিয়ে systemGestureExclusionRects() কল করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
    // Finally pass our updated list of rectangles to the system
    systemGestureExclusionRects = gestureExclusionRects
}
  1. onDraw() বা onLayout() থেকে updateGestureExclusion() মেথডটি কল করুন। onDraw() ওভাররাইড করুন এবং updateGestureExclusion এর একটি কল যুক্ত করুন।

MySeekBar.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    updateGestureExclusion()
}
  1. আপনাকে অবশ্যই SeekBar রেফারেন্সগুলো আপডেট করতে হবে। শুরু করার জন্য, fragment_nowplaying.xml ফাইলটি খুলুন।
  2. SeekBar com.example.android.uamp.view.MySeekBar এ পরিবর্তন করুন।

fragment_nowplaying.xml এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

<com.example.android.uamp.view.MySeekBar
    android:id="@+id/seekBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="parent" />
  1. NowPlayingFragment.ktSeekBar রেফারেন্সগুলো আপডেট করতে, NowPlayingFragment.kt ফাইলটি খুলুন এবং positionSeekBar এর টাইপ পরিবর্তন করে MySeekBar করুন। ভ্যারিয়েবল টাইপের সাথে মেলানোর জন্য, findViewById কলের জন্য SeekBar জেনেরিকস পরিবর্তন করে MySeekBar করুন।

NowPlayingFragment.kt এর নিম্নলিখিত কোড নমুনাটি পর্যালোচনা করুন:

val positionSeekBar: MySeekBar = view.findViewById<MySeekBar>(
     R.id.seekBar
).apply { progress = 0 }
  1. অ্যাপটি চালান এবং SeekBar এর সাথে ইন্টারঅ্যাক্ট করুন। এরপরও যদি আপনি জেসচার কনফ্লিক্টের সম্মুখীন হন, তবে আপনি MySeekBar এ থাম্ব বাউন্ডস পরীক্ষা ও পরিবর্তন করে দেখতে পারেন। খেয়াল রাখবেন যেন প্রয়োজনের চেয়ে বড় জেসচার এক্সক্লুশন জোন তৈরি না করেন, কারণ এটি অন্যান্য সম্ভাব্য জেসচার এক্সক্লুশন কলকে সীমিত করে এবং ব্যবহারকারীর জন্য অসামঞ্জস্যপূর্ণ আচরণ তৈরি করে।

৭. অভিনন্দন

অভিনন্দন! আপনি সিস্টেম জেসচার ব্যবহার করে দ্বন্দ্ব এড়ানো এবং সমাধান করার পদ্ধতি শিখেছেন!

আপনি এজ-টু-এজ এক্সটেন্ড করে এবং অ্যাপ কন্ট্রোলগুলোকে জেসচার জোন থেকে দূরে সরাতে ইনসেট ব্যবহার করে আপনার অ্যাপটিকে ফুল-স্ক্রিনে পরিণত করেছেন। আপনি অ্যাপ কন্ট্রোলগুলোতে সিস্টেম ব্যাক জেসচার নিষ্ক্রিয় করার পদ্ধতিও শিখেছেন।

আপনার অ্যাপগুলোকে সিস্টেম জেসচারের সাথে কাজ করানোর জন্য প্রয়োজনীয় মূল ধাপগুলো এখন আপনি জানেন!

অতিরিক্ত উপকরণ

রেফারেন্স নথি