জেটপ্যাক কম্পোজ দিয়ে অভিযোজিত অ্যাপ তৈরি করুন

1। পরিচিতি

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

আমরা ডুব দেওয়ার আগে, অভিযোজনযোগ্যতা বলতে আমরা কী বুঝি তা বোঝা গুরুত্বপূর্ণ।

অভিযোজনযোগ্যতা

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

আরও জানতে, অভিযোজিত নকশা দেখুন।

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

আপনি কি শিখবেন

  • জেটপ্যাক কম্পোজের মাধ্যমে সমস্ত উইন্ডোর আকার লক্ষ্য করার জন্য কীভাবে আপনার অ্যাপ ডিজাইন করবেন।
  • কিভাবে বিভিন্ন ফোল্ডেবলের জন্য আপনার অ্যাপ টার্গেট করবেন।
  • ভাল নাগালযোগ্যতা এবং অ্যাক্সেসযোগ্যতার জন্য কীভাবে বিভিন্ন ধরণের নেভিগেশন ব্যবহার করবেন।
  • প্রতিটি উইন্ডো আকারের জন্য সেরা অভিজ্ঞতা প্রদান করতে উপাদান 3 উপাদানগুলি কীভাবে ব্যবহার করবেন।

আপনি কি প্রয়োজন হবে

আপনি এই কোডল্যাবের জন্য রিসাইজযোগ্য এমুলেটর ব্যবহার করবেন, যা আপনাকে বিভিন্ন ধরণের ডিভাইস এবং উইন্ডো আকারের মধ্যে স্যুইচ করতে দেয়।

ফোন, উন্মোচিত, ট্যাবলেট এবং ডেস্কটপের বিকল্পগুলির সাথে আকার পরিবর্তনযোগ্য এমুলেটর।

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

আপনি কি নির্মাণ করবেন

  • অভিযোজিত ডিজাইন, বিভিন্ন উপাদান নেভিগেশন এবং সর্বোত্তম স্ক্রীন স্পেস ব্যবহারের জন্য সর্বোত্তম অনুশীলন ব্যবহার করে একটি ইন্টারেক্টিভ ইমেল ক্লায়েন্ট অ্যাপ।

একাধিক ডিভাইস সমর্থন শোকেস যা আপনি এই কোডল্যাবে অর্জন করবেন

2. সেট আপ করুন

এই কোডল্যাবের জন্য কোড পেতে, কমান্ড লাইন থেকে GitHub সংগ্রহস্থল ক্লোন করুন:

git clone https://github.com/android/codelab-android-compose.git
cd codelab-android-compose/AdaptiveUiCodelab

বিকল্পভাবে, আপনি একটি জিপ ফাইল হিসাবে সংগ্রহস্থল ডাউনলোড করতে পারেন:

আমরা সুপারিশ করি যে আপনি মূল শাখার কোড দিয়ে শুরু করুন এবং আপনার নিজস্ব গতিতে ধাপে ধাপে কোডল্যাব অনুসরণ করুন।

অ্যান্ড্রয়েড স্টুডিওতে প্রজেক্ট খুলুন

  1. অ্যান্ড্রয়েড স্টুডিওতে স্বাগতম উইন্ডোতে, নির্বাচন করুন c01826594f360d94.png একটি বিদ্যমান প্রকল্প খুলুন।
  2. <Download Location>/AdaptiveUiCodelab ফোল্ডারটি নির্বাচন করুন (নিশ্চিত করুন যে আপনি build.gradle ধারণকারী AdaptiveUiCodelab ডিরেক্টরি নির্বাচন করেছেন)।
  3. অ্যান্ড্রয়েড স্টুডিও যখন প্রকল্পটি আমদানি করেছে, তখন পরীক্ষা করুন যে আপনি main শাখা চালাতে পারেন।

শুরু কোড অন্বেষণ

প্রধান শাখা কোডে ui প্যাকেজ থাকে। আপনি সেই প্যাকেজে নিম্নলিখিত ফাইলগুলির সাথে কাজ করবেন:

  • MainActivity.kt - এন্ট্রি পয়েন্ট অ্যাক্টিভিটি যেখানে আপনি আপনার অ্যাপ শুরু করেন।
  • ReplyApp.kt - প্রধান স্ক্রীন UI কম্পোজেবল ধারণ করে।
  • ReplyHomeViewModel.kt - অ্যাপের বিষয়বস্তুর জন্য ডেটা এবং UI অবস্থা প্রদান করে।
  • ReplyListContent.kt - তালিকা এবং বিস্তারিত স্ক্রীন প্রদানের জন্য কম্পোজেবল রয়েছে।

আপনি প্রথমে MainActivity.kt এ ফোকাস করবেন।

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContent {
        ReplyTheme {
            val uiState by viewModel.uiState.collectAsStateWithLifecycle()
            ReplyApp(
                replyHomeUIState = uiState,
                onEmailClick = viewModel::setSelectedEmail
            )
        }
    }
}

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

ফোনে প্রাথমিক স্ক্রীন

ট্যাবলেটে প্রাথমিক প্রসারিত দৃশ্য

আপনি স্ক্রিনের জায়গার সুবিধা নিতে, ব্যবহারযোগ্যতা বাড়াতে এবং সামগ্রিক ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে এটি আপডেট করবেন।

3. অ্যাপগুলিকে অভিযোজিত করুন৷

এই বিভাগে অ্যাপগুলিকে অভিযোজিত করার অর্থ কী এবং উপাদান 3 এটিকে আরও সহজ করার জন্য কী উপাদান সরবরাহ করে তা উপস্থাপন করে৷ এটি ফোন, ট্যাবলেট, বড় ট্যাবলেট এবং ফোল্ডেবল সহ আপনি যে ধরণের স্ক্রীন এবং রাজ্যগুলিকে টার্গেট করবেন তাও কভার করে৷

আপনি উইন্ডোর আকার, ভাঁজ ভঙ্গি এবং বিভিন্ন ধরণের নেভিগেশন বিকল্পগুলির মৌলিক বিষয়গুলি দিয়ে শুরু করবেন। তারপরে, আপনি এটিকে আরও অভিযোজিত করতে আপনার অ্যাপে এই APIগুলি ব্যবহার করতে পারেন।

জানালার মাপ

অ্যান্ড্রয়েড ডিভাইসগুলি ফোন থেকে ফোল্ডেবল থেকে ট্যাবলেট এবং ChromeOS ডিভাইস পর্যন্ত সমস্ত আকার এবং আকারে আসে৷ যতটা সম্ভব উইন্ডো আকার সমর্থন করার জন্য, আপনার UI কে প্রতিক্রিয়াশীল এবং অভিযোজিত হতে হবে। আপনার অ্যাপের UI পরিবর্তন করার জন্য সঠিক প্রান্তিকে খুঁজে পেতে আপনাকে সাহায্য করার জন্য, আমরা ব্রেকপয়েন্ট মানগুলি সংজ্ঞায়িত করেছি যা ডিভাইসগুলিকে পূর্বনির্ধারিত আকারের ক্লাসে (কম্প্যাক্ট, মাঝারি এবং প্রসারিত) শ্রেণীবদ্ধ করতে সাহায্য করে, যাকে উইন্ডো সাইজ ক্লাস বলা হয়। এগুলি মতামতযুক্ত ভিউপোর্ট ব্রেকপয়েন্টগুলির একটি সেট যা আপনাকে প্রতিক্রিয়াশীল এবং অভিযোজিত অ্যাপ্লিকেশন লেআউটগুলি ডিজাইন, বিকাশ এবং পরীক্ষা করতে সহায়তা করে৷

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

কমপ্যাক্ট, মাঝারি এবং প্রসারিত প্রস্থের জন্য WindowWidthSizeClass।

কমপ্যাক্ট, মাঝারি এবং প্রসারিত উচ্চতার জন্য WindowHeightSizeClass।

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

ভাঁজ রাষ্ট্র

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

ভাঁজযোগ্য ভঙ্গি, সমতল এবং অর্ধ-খোলা

অতিরিক্তভাবে, কবজাটি আংশিকভাবে খোলা থাকা অবস্থায় ব্যবহারকারী ভিতরের ডিসপ্লেটির দিকে তাকাতে পারে, যার ফলে ভাঁজের অভিযোজনের উপর ভিত্তি করে বিভিন্ন শারীরিক ভঙ্গি তৈরি হয়: ট্যাবলেটপ ভঙ্গি (উপরের ছবিতে ডানদিকে দেখানো হয়েছে) এবং বুক ভঙ্গি ( উল্লম্ব ভাঁজ)।

ভাঁজ ভঙ্গি এবং কব্জা সম্পর্কে আরও পড়ুন।

ভাঁজযোগ্য লেআউটগুলিকে সমর্থন করে এমন অভিযোজিত বিন্যাসগুলি প্রয়োগ করার সময় এই সমস্তগুলি বিবেচনা করার বিষয়।

অভিযোজিত তথ্য পান

Material3 adaptive লাইব্রেরি আপনার অ্যাপটি যে উইন্ডোতে চলছে সে সম্পর্কে তথ্যে সুবিধাজনক অ্যাক্সেস প্রদান করে।

  1. সংস্করণ ক্যাটালগ ফাইলে এই শিল্পকর্ম এবং এর সংস্করণের জন্য এন্ট্রি যোগ করুন:

gradle/libs.versions.toml

[versions]
material3Adaptive = "1.0.0-beta01"

[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
  1. অ্যাপ মডিউলের বিল্ড ফাইলে, নতুন লাইব্রেরি নির্ভরতা যোগ করুন এবং তারপর একটি গ্রেডল সিঙ্ক সঞ্চালন করুন:

app/build.gradle.kts

dependencies {

    implementation(libs.androidx.material3.adaptive)
}

এখন, যেকোন কম্পোজেবল স্কোপে, আপনি একটি WindowAdaptiveInfo অবজেক্ট পেতে বর্তমান উইন্ডো সাইজ ক্লাসের মতো তথ্য এবং ডিভাইসটি ট্যাবলেটপ ভঙ্গির মতো ভাঁজযোগ্য ভঙ্গিতে আছে কিনা তা পেতে currentWindowAdaptiveInfo() ব্যবহার করতে পারেন।

আপনি এখন MainActivity এ এটি চেষ্টা করতে পারেন।

  1. ReplyTheme ব্লকের ভিতরে onCreate() এ, উইন্ডো অভিযোজিত তথ্য পান এবং একটি Text কম্পোজযোগ্য আকারের ক্লাসগুলি প্রদর্শন করুন (আপনি ReplyApp() উপাদানের পরে এটি যোগ করতে পারেন):

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContent {
        ReplyTheme {
            val uiState by viewModel.uiState.collectAsStateWithLifecycle()
            ReplyApp(
                replyHomeUIState = uiState,
                onEmailClick = viewModel::setSelectedEmail
            )

            val adaptiveInfo = currentWindowAdaptiveInfo()
            val sizeClassText =
                "${adaptiveInfo.windowSizeClass.windowWidthSizeClass}\n" +
                "${adaptiveInfo.windowSizeClass.windowHeightSizeClass}"
            Text(
                text = sizeClassText,
                color = Color.Magenta,
                modifier = Modifier.padding(20.dp)
            )
        }
    }
}

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

4. গতিশীল নেভিগেশন

এখন আপনি অ্যাক্সেসযোগ্যতা উন্নত করার জন্য ডিভাইসের অবস্থা এবং আকার পরিবর্তন হিসাবে অ্যাপের নেভিগেশন মানিয়ে নেবেন।

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

  • ডিভাইসটি ধরে রাখার সময় কোন এলাকায় পৌঁছানো আরামদায়ক?
  • কোন এলাকায় শুধুমাত্র আঙ্গুল প্রসারিত করা যেতে পারে, যা অসুবিধাজনক হতে পারে?
  • কোন এলাকায় পৌঁছানো চ্যালেঞ্জিং বা ব্যবহারকারী যেখানে ডিভাইসটি ধরে রেখেছে সেখান থেকে অনেক দূরে?

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

নীচের নেভিগেশন

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

আইটেম সহ নীচের নেভিগেশন বার

একটি মাঝারি প্রস্থের জানালার আকারের জন্য, ন্যাভিগেশন রেলটি পৌঁছানোর জন্য আদর্শ কারণ আমাদের থাম্বটি স্বাভাবিকভাবেই ডিভাইসের পাশে পড়ে। আপনি আরও তথ্য দেখানোর জন্য একটি নেভিগেশন ড্রয়ারের সাথে একটি নেভিগেশন রেলকে একত্রিত করতে পারেন।

আইটেম সঙ্গে নেভিগেশন রেল

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

মোডাল নেভিগেশন ড্রয়ার

আপনি কমপ্যাক্ট থেকে মাঝারি আকারের ফোন এবং ট্যাবলেটগুলির জন্য একটি মোডাল নেভিগেশন ড্রয়ার ব্যবহার করতে পারেন কারণ এটি বিষয়বস্তুর উপর ওভারলে হিসাবে প্রসারিত বা লুকানো যেতে পারে। এটি কখনও কখনও একটি নেভিগেশন রেলের সাথে মিলিত হতে পারে।

আইটেম সহ মডেল নেভিগেশন ড্রয়ার

স্থায়ী নেভিগেশন ড্রয়ার

আপনি বড় ট্যাবলেট, ক্রোমবুক এবং ডেস্কটপে স্থায়ী নেভিগেশনের জন্য একটি স্থায়ী নেভিগেশন ড্রয়ার ব্যবহার করতে পারেন।

আইটেম সহ স্থায়ী নেভিগেশন ড্রয়ার

গতিশীল নেভিগেশন বাস্তবায়ন

এখন, ডিভাইসের অবস্থা এবং আকার পরিবর্তনের সাথে সাথে আপনি বিভিন্ন ধরণের নেভিগেশনের মধ্যে স্যুইচ করবেন।

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

  1. সংস্করণ ক্যাটালগ এবং অ্যাপের বিল্ড স্ক্রিপ্ট আপডেট করে এই উপাদানটি পেতে Gradle নির্ভরতা যোগ করুন, তারপর একটি Gradle সিঙ্ক করুন:

gradle/libs.versions.toml

[versions]
material3AdaptiveNavSuite = "1.3.0-beta01"

[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavSuite" }

app/build.gradle.kts

dependencies {

    implementation(libs.androidx.material3.adaptive.navigation.suite)
}
  1. ReplyApp.ktReplyNavigationWrapper() কম্পোজযোগ্য ফাংশন খুঁজুন এবং Column এবং এর বিষয়বস্তু একটি NavigationSuiteScaffold দিয়ে প্রতিস্থাপন করুন:

ReplyApp.kt

@Composable
private fun ReplyNavigationWrapperUI(
    content: @Composable () -> Unit = {}
) {
    var selectedDestination: ReplyDestination by remember {
        mutableStateOf(ReplyDestination.Inbox)
    }

    NavigationSuiteScaffold(
        navigationSuiteItems = {
            ReplyDestination.entries.forEach {
                item(
                    selected = it == selectedDestination,
                    onClick = { /*TODO update selection*/ },
                    icon = {
                        Icon(
                            imageVector = it.icon,
                            contentDescription = stringResource(it.labelRes)
                        )
                    },
                    label = {
                        Text(text = stringResource(it.labelRes))
                    },
                )
            }
        }
    ) {
        content()
    }
}

navigationSuiteItems আর্গুমেন্ট হল একটি ব্লক যা আপনাকে item() ফাংশন ব্যবহার করে আইটেম যোগ করতে দেয়, যেমন একটি LazyColumn এ আইটেম যোগ করা। ট্রেলিং ল্যাম্বডা-এর ভিতরে, এই কোডটি ReplyNavigationWrapperUI() -এ একটি আর্গুমেন্ট হিসাবে পাস করা content() কে কল করে।

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

খুব প্রশস্ত উইন্ডোতে, যেমন ল্যান্ডস্কেপে ট্যাবলেটে, আপনি স্থায়ী নেভিগেশন ড্রয়ার দেখাতে চাইতে পারেন। NavigationSuiteScaffold একটি স্থায়ী ড্রয়ার দেখানো সমর্থন করে, যদিও এটি বর্তমান WindowWidthSizeClass মানের কোনোটিতে দেখানো হয়নি। যাইহোক, আপনি এটি একটি ছোট পরিবর্তন সঙ্গে এটি করতে পারেন.

  1. NavigationSuiteScaffold এ কল করার ঠিক আগে নিম্নলিখিত কোড যোগ করুন:

ReplyApp.kt

@Composable
private fun ReplyNavigationWrapperUI(
    content: @Composable () -> Unit = {}
) {
    var selectedDestination: ReplyDestination by remember {
        mutableStateOf(ReplyDestination.Inbox)
    }

    val windowSize = with(LocalDensity.current) {
        currentWindowSize().toSize().toDpSize()
    }
    val layoutType = if (windowSize.width >= 1200.dp) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(
            currentWindowAdaptiveInfo()
        )
    }

    NavigationSuiteScaffold(
        layoutType = layoutType,
        ...
    ) {
        content()
    }
}

এই কোডটি প্রথমে উইন্ডোর আকার পায় এবং currentWindowSize() এবং LocalDensity.current ব্যবহার করে এটিকে ডিপি ইউনিটে রূপান্তর করে এবং তারপরে নেভিগেশন UI এর লেআউটের ধরণ নির্ধারণ করতে উইন্ডোর প্রস্থের তুলনা করে। উইন্ডোর প্রস্থ কমপক্ষে 1200.dp হলে, এটি NavigationSuiteType.NavigationDrawer ব্যবহার করে। অন্যথায়, এটি ডিফল্ট গণনায় ফিরে আসে।

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

বিভিন্ন আকারের ডিভাইসের জন্য অভিযোজনযোগ্যতার পরিবর্তন দেখানো হচ্ছে।

অভিনন্দন, আপনি বিভিন্ন ধরণের উইন্ডোর আকার এবং অবস্থা সমর্থন করার জন্য বিভিন্ন ধরণের নেভিগেশন সম্পর্কে শিখেছেন!

পরবর্তী বিভাগে, আপনি একই তালিকা আইটেম প্রান্ত থেকে প্রান্ত প্রসারিত করার পরিবর্তে যে কোনও অবশিষ্ট স্ক্রীন এলাকার সুবিধা নেওয়ার উপায় অন্বেষণ করবেন।

5. পর্দা স্থান ব্যবহার

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

উপাদান 3 তিনটি ক্যানোনিকাল লেআউটকে সংজ্ঞায়িত করে যার প্রতিটিতে কমপ্যাক্ট, মাঝারি এবং প্রসারিত উইন্ডো আকারের ক্লাসের জন্য কনফিগারেশন রয়েছে। লিস্ট ডিটেইল ক্যানোনিকাল লেআউট এই ব্যবহারের ক্ষেত্রে নিখুঁত, এবং ListDetailPaneScaffold হিসাবে কম্পোজে উপলব্ধ।

  1. নিম্নলিখিত নির্ভরতা যোগ করে এবং একটি Gradle সিঙ্ক সম্পাদন করে এই উপাদানটি পান:

gradle/libs.versions.toml

[versions]
material3Adaptive = "1.0.0-beta01"

[libraries]
androidx-material3-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "material3Adaptive" }
androidx-material3-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "material3Adaptive" }

app/build.gradle.kts

dependencies {

    implementation(libs.androidx.material3.adaptive.layout)
    implementation(libs.androidx.material3.adaptive.navigation)
}
  1. ReplyApp.ktReplyAppContent() কম্পোজযোগ্য ফাংশন খুঁজুন, যা বর্তমানে ReplyListPane() কল করে শুধুমাত্র তালিকা ফলকটি দেখায়। নিম্নলিখিত কোড সন্নিবেশ করে ListDetailPaneScaffold এর সাথে এই বাস্তবায়ন প্রতিস্থাপন করুন। যেহেতু এটি একটি পরীক্ষামূলক API, তাই আপনি ReplyAppContent() ফাংশনে @OptIn টীকাও যোগ করবেন:

ReplyApp.kt

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
    replyHomeUIState: ReplyHomeUIState,
    onEmailClick: (Email) -> Unit,
) {
    val navigator = rememberListDetailPaneScaffoldNavigator<Long>()

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            ReplyListPane(replyHomeUIState, onEmailClick)
        },
        detailPane = {
            ReplyDetailPane(replyHomeUIState.emails.first())
        }
    )
}

এই কোডটি প্রথমে rememberListDetailPaneNavigator () ব্যবহার করে একটি নেভিগেটর তৈরি করে rememberListDetailPaneNavigator () কোন ফলকটি প্রদর্শিত হবে এবং সেই ফলকে কোন বিষয়বস্তু উপস্থাপন করা উচিত তার উপর নেভিগেটর কিছু নিয়ন্ত্রণ প্রদান করে, যা পরে প্রদর্শিত হবে।

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

বাকি প্রয়োজনীয় প্যারামিটারগুলি হল প্যানের জন্য কম্পোজেবল ল্যাম্বডাস। ReplyListPane() এবং ReplyDetailPane() ( ReplyListContent.kt এ পাওয়া যায়) যথাক্রমে তালিকা এবং বিস্তারিত প্যানের ভূমিকা পূরণ করতে ব্যবহৃত হয়। ReplyDetailPane() একটি ইমেল আর্গুমেন্ট আশা করে, তাই আপাতত এই কোডটি ReplyHomeUIState এ ইমেলের তালিকা থেকে প্রথম ইমেল ব্যবহার করে।

দুটি ফলক বিন্যাস দেখতে অ্যাপটি চালান এবং এমুলেটর ভিউটিকে ভাঁজযোগ্য বা ট্যাবলেটে স্যুইচ করুন (আপনাকে অভিযোজন পরিবর্তন করতে হতে পারে)। এটি ইতিমধ্যে আগের চেয়ে অনেক ভাল দেখাচ্ছে!

এখন এই পর্দার কাঙ্ক্ষিত আচরণের কিছু সম্বোধন করা যাক। যখন ব্যবহারকারী তালিকা ফলকে একটি ইমেলে ট্যাপ করে, তখন এটি সমস্ত উত্তরের সাথে বিস্তারিত ফলকে দেখানো উচিত। বর্তমানে, অ্যাপটি কোন ইমেল নির্বাচন করা হয়েছে তার ট্র্যাক রাখে না এবং একটি আইটেম ট্যাপ করলে কিছুই হয় না। ReplyHomeUIState এর বাকি UI অবস্থার সাথে এই তথ্য রাখার সর্বোত্তম জায়গা।

  1. ReplyHomeViewModel.kt খুলুন এবং ReplyHomeUIState ডেটা ক্লাস খুঁজুন। null এর একটি ডিফল্ট মান সহ নির্বাচিত ইমেলের জন্য একটি সম্পত্তি যোগ করুন:

ReplyHomeViewModel.kt

data class ReplyHomeUIState(
    val emails : List<Email> = emptyList(),
    val selectedEmail: Email? = null,
    val loading: Boolean = false,
    val error: String? = null
)
  1. একই ফাইলে, ReplyHomeViewModel এর একটি setSelectedEmail() ফাংশন রয়েছে যা ব্যবহারকারী যখন একটি তালিকা আইটেম ট্যাপ করে তখন বলা হয়। UI অবস্থা অনুলিপি করতে এবং নির্বাচিত ইমেল রেকর্ড করতে এই ফাংশনটি পরিবর্তন করুন:

ReplyHomeViewModel.kt

fun setSelectedEmail(email: Email) {
    _uiState.update {
        it.copy(selectedEmail = email)
    }
}

ব্যবহারকারীর কোনো আইটেম ট্যাপ করার আগে এবং নির্বাচিত ইমেলটি null হওয়ার আগে কী ঘটে তা বিবেচনা করার মতো কিছু। বিস্তারিত ফলকে কি প্রদর্শন করা উচিত? এই কেসটি পরিচালনা করার একাধিক উপায় রয়েছে, যেমন ডিফল্টরূপে তালিকায় প্রথম আইটেমটি দেখানো।

  1. একই ফাইলে, observeEmails() ফাংশন পরিবর্তন করুন। যখন ইমেলের তালিকা লোড করা হয়, যদি পূর্ববর্তী UI রাজ্যে একটি নির্বাচিত ইমেল না থাকে, তাহলে এটিকে প্রথম আইটেমে সেট করুন:

ReplyHomeViewModel.kt

private fun observeEmails() {
    viewModelScope.launch {
        emailsRepository.getAllEmails()
            .catch { ex ->
                _uiState.value = ReplyHomeUIState(error = ex.message)
            }
            .collect { emails ->
                val currentSelection = _uiState.value.selectedEmail
                _uiState.value = ReplyHomeUIState(
                    emails = emails,
                    selectedEmail = currentSelection ?: emails.first()
                )
            }
    }
}
  1. ReplyApp.kt এ ফিরে যান এবং নির্বাচিত ইমেলটি ব্যবহার করুন, যদি এটি উপলব্ধ থাকে, তাহলে বিস্তারিত ফলক বিষয়বস্তু তৈরি করতে:

ReplyApp.kt

ListDetailPaneScaffold(
    // ...
    detailPane = {
        if (replyHomeUIState.selectedEmail != null) {
            ReplyDetailPane(replyHomeUIState.selectedEmail)
        }
    }
)

অ্যাপটি আবার চালান এবং এমুলেটরটিকে ট্যাবলেট আকারে স্যুইচ করুন এবং দেখুন যে একটি তালিকা আইটেমে আলতো চাপলে বিস্তারিত ফলকের বিষয়বস্তু আপডেট হয়।

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

  1. এটি ঠিক করতে, ল্যাম্বডা ReplyListPane এ পাস করার সাথে সাথে নিম্নলিখিত কোডটি ঢোকান:

ReplyApp.kt

ListDetailPaneScaffold(
    // ...
    listPane = {
        ReplyListPane(
            replyHomeUIState = replyHomeUIState,
            onEmailClick = { email ->
                onEmailClick(email)
                navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
            }
        )
    },
    // ...
)

এই lambda একটি আইটেম ক্লিক করা হলে অতিরিক্ত আচরণ যোগ করার জন্য আগে তৈরি ন্যাভিগেটর ব্যবহার করে। এটি এই ফাংশনে পাস করা আসল ল্যাম্বডাকে কল করবে এবং তারপর কোন প্যানটি দেখানো হবে তা নির্দিষ্ট করে navigator.navigateTo() কল করবে। স্ক্যাফোল্ডের প্রতিটি ফলকের সাথে একটি ভূমিকা যুক্ত থাকে এবং বিস্তারিত ফলকের জন্য এটি ListDetailPaneScaffoldRole.Detail । ছোট উইন্ডোতে, এটি অ্যাপটিকে সামনে নেভিগেট করার মতো চেহারা দেবে।

ব্যবহারকারী বিশদ ফলক থেকে পিছনের বোতাম টিপলে কী ঘটবে তাও অ্যাপটিকে পরিচালনা করতে হবে এবং একটি ফলক বা দুটি প্যান দৃশ্যমান কিনা তার উপর নির্ভর করে এই আচরণটি ভিন্ন হবে৷

  1. নিম্নলিখিত কোড যোগ করে ব্যাক নেভিগেশন সমর্থন.

ReplyApp.kt

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
    replyHomeUIState: ReplyHomeUIState,
    onEmailClick: (Email) -> Unit,
) {
    val navigator = rememberListDetailPaneScaffoldNavigator<Long>()

    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                ReplyListPane(
                    replyHomeUIState = replyHomeUIState,
                    onEmailClick = { email ->
                        onEmailClick(email)
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
                    }
                )
            }
        },
        detailPane = {
            AnimatedPane {
                if (replyHomeUIState.selectedEmail != null) {
                    ReplyDetailPane(replyHomeUIState.selectedEmail)
                }
            }
        }
    )
}

নেভিগেটর ListDetailPaneScaffold এর সম্পূর্ণ অবস্থা জানে, ব্যাক নেভিগেশন সম্ভব কিনা এবং এই সমস্ত পরিস্থিতিতে কি করতে হবে। এই কোডটি একটি BackHandler তৈরি করে যেটি সক্রিয় হয় যখনই নেভিগেটর আবার নেভিগেট করতে পারে, এবং lambda এর ভিতরে navigateBack() কল করে। এছাড়াও, প্যানগুলির মধ্যে রূপান্তরটি আরও মসৃণ করতে, প্রতিটি ফলক একটি AnimatedPane() কম্পোজযোগ্যভাবে মোড়ানো হয়।

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

বিভিন্ন আকারের ডিভাইসের জন্য অভিযোজনযোগ্যতার পরিবর্তন দেখানো হচ্ছে।

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

6. অভিনন্দন

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

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

এরপর কি?

রচনা পথের অন্যান্য কোডল্যাবগুলি দেখুন।

নমুনা অ্যাপ্লিকেশন

  • রচনার নমুনাগুলি হল অনেকগুলি অ্যাপের একটি সংগ্রহ যা কোডল্যাবগুলিতে ব্যাখ্যা করা সেরা অনুশীলনগুলিকে অন্তর্ভুক্ত করে৷

রেফারেন্স ডক্স