1. ভূমিকা
এই কোডল্যাবে আপনি শিখবেন কিভাবে ফোন, ট্যাবলেট এবং ফোল্ডেবলের জন্য অ্যাডাপ্টিভ অ্যাপ তৈরি করতে হয় এবং জেটপ্যাক কম্পোজের মাধ্যমে কীভাবে এগুলো সহজলভ্যতা বৃদ্ধি করে। আপনি ম্যাটেরিয়াল ৩ কম্পোনেন্ট এবং থিমিং ব্যবহারের জন্য সেরা অনুশীলনগুলিও শিখবেন।
আমরা আরও গভীরে যাওয়ার আগে, অভিযোজনযোগ্যতা বলতে আমরা কী বোঝাতে চাই তা বোঝা গুরুত্বপূর্ণ।
অভিযোজনযোগ্যতা
আপনার অ্যাপের UI বিভিন্ন উইন্ডোর আকার, ওরিয়েন্টেশন এবং ফর্ম ফ্যাক্টরের উপর নির্ভর করে প্রতিক্রিয়াশীল হওয়া উচিত। একটি অভিযোজিত লেআউট তার জন্য উপলব্ধ স্ক্রিন স্পেসের উপর ভিত্তি করে পরিবর্তিত হয়। এই পরিবর্তনগুলি স্থান পূরণের জন্য সহজ লেআউট সমন্বয় থেকে শুরু করে, নির্দিষ্ট নেভিগেশন স্টাইল নির্বাচন করা, অতিরিক্ত স্থান ব্যবহার করার জন্য সম্পূর্ণরূপে লেআউট পরিবর্তন করা পর্যন্ত।
আরও জানতে, অ্যাডাপ্টিভ ডিজাইন দেখুন।
এই কোডল্যাবে, আপনি জেটপ্যাক কম্পোজ ব্যবহার করার সময় অভিযোজনযোগ্যতা কীভাবে ব্যবহার করবেন এবং সে সম্পর্কে চিন্তাভাবনা করবেন তা অন্বেষণ করবেন। আপনি রিপ্লাই নামে একটি অ্যাপ্লিকেশন তৈরি করেন, যা আপনাকে দেখায় যে কীভাবে সমস্ত ধরণের স্ক্রিনের জন্য অভিযোজনযোগ্যতা বাস্তবায়ন করতে হয় এবং ব্যবহারকারীদের সর্বোত্তম অভিজ্ঞতা দেওয়ার জন্য অভিযোজনযোগ্যতা এবং পৌঁছানোযোগ্যতা একসাথে কাজ করে।
তুমি কি শিখবে
- জেটপ্যাক কম্পোজের সাহায্যে সমস্ত উইন্ডো আকারের জন্য আপনার অ্যাপটি কীভাবে ডিজাইন করবেন।
- বিভিন্ন ফোল্ডেবলের জন্য আপনার অ্যাপকে কীভাবে লক্ষ্য করবেন।
- আরও ভালোভাবে পৌঁছানো এবং অ্যাক্সেসযোগ্যতার জন্য বিভিন্ন ধরণের নেভিগেশন কীভাবে ব্যবহার করবেন।
- প্রতিটি আকারের জানালার জন্য সর্বোত্তম অভিজ্ঞতা প্রদানের জন্য ম্যাটেরিয়াল 3 উপাদানগুলি কীভাবে ব্যবহার করবেন।
তোমার যা লাগবে
- অ্যান্ড্রয়েড স্টুডিওর সর্বশেষ স্থিতিশীল সংস্করণ।
- একটি অ্যান্ড্রয়েড ১৩ রিসাইজেবল ভার্চুয়াল ডিভাইস ।
- কোটলিন সম্পর্কে জ্ঞান।
- কম্পোজের প্রাথমিক ধারণা (যেমন
@Composableটীকা)। - কম্পোজ লেআউটের সাথে প্রাথমিক পরিচিতি (যেমন
RowএবংColumn)। - মডিফায়ারের সাথে প্রাথমিক পরিচিতি (যেমন
Modifier.padding())।
এই কোডল্যাবের জন্য আপনি রিসাইজেবল এমুলেটর ব্যবহার করবেন, যা আপনাকে বিভিন্ন ধরণের ডিভাইস এবং উইন্ডো আকারের মধ্যে স্যুইচ করতে দেয়।

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

2. সেট আপ করুন
এই কোডল্যাবের কোড পেতে, কমান্ড লাইন থেকে GitHub রিপোজিটরিটি ক্লোন করুন:
git clone https://github.com/android/codelab-android-compose.git cd codelab-android-compose/AdaptiveUiCodelab
বিকল্পভাবে, আপনি সংগ্রহস্থলটি একটি জিপ ফাইল হিসাবে ডাউনলোড করতে পারেন:
আমরা আপনাকে প্রধান শাখার কোড দিয়ে শুরু করার পরামর্শ দিচ্ছি এবং আপনার নিজস্ব গতিতে ধাপে ধাপে কোডল্যাব অনুসরণ করুন।
অ্যান্ড্রয়েড স্টুডিওতে প্রকল্পটি খুলুন।
- Welcome to Android Studio উইন্ডোতে, নির্বাচন করুন
একটি বিদ্যমান প্রকল্প খুলুন। -
<Download Location>/AdaptiveUiCodelabফোল্ডারটি নির্বাচন করুন (build.gradleধারণকারীAdaptiveUiCodelabডিরেক্টরিটি নির্বাচন করুন)। - অ্যান্ড্রয়েড স্টুডিও যখন প্রকল্পটি আমদানি করে, তখন পরীক্ষা করে দেখুন যে আপনি
mainশাখাটি চালাতে পারেন।
শুরুর কোডটি অন্বেষণ করুন
প্রধান শাখা কোডে ui প্যাকেজ রয়েছে। আপনি সেই প্যাকেজে নিম্নলিখিত ফাইলগুলি নিয়ে কাজ করবেন:
-
MainActivity.kt- এন্ট্রি পয়েন্ট অ্যাক্টিভিটি যেখানে আপনি আপনার অ্যাপ শুরু করেন। -
ReplyApp.kt- প্রধান স্ক্রিন UI কম্পোজেবল ধারণ করে। -
ReplyHomeViewModel.kt- অ্যাপের কন্টেন্টের ডেটা এবং UI অবস্থা প্রদান করে। -
ReplyListContent.kt- তালিকা এবং বিস্তারিত স্ক্রিন প্রদানের জন্য কম্পোজেবল রয়েছে।
আপনি যদি এই অ্যাপটি একটি রিসাইজেবল এমুলেটরে চালান এবং ফোন বা ট্যাবলেটের মতো বিভিন্ন ধরণের ডিভাইস ব্যবহার করে দেখেন, তাহলে স্ক্রিন স্পেসের সুবিধা নেওয়ার বা রিচেবিলিটি এরগনোমিক্স প্রদানের পরিবর্তে UI কেবল নির্দিষ্ট স্থানে প্রসারিত হয়।


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


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

অতিরিক্তভাবে, ব্যবহারকারী হয়তো ভেতরের ডিসপ্লের দিকে তাকাচ্ছেন যখন কব্জাটি আংশিকভাবে খোলা থাকে, যার ফলে ভাঁজের অবস্থানের উপর ভিত্তি করে বিভিন্ন শারীরিক ভঙ্গি তৈরি হয়: টেবিলটপ ভঙ্গি (উপরের ছবিতে ডানদিকে দেখানো অনুভূমিক ভাঁজ) এবং বই ভঙ্গি (উল্লম্ব ভাঁজ)।
ভাঁজ ভঙ্গি এবং কব্জা সম্পর্কে আরও পড়ুন।
ফোল্ডেবল সমর্থনকারী অভিযোজিত লেআউট বাস্তবায়নের সময় এই সমস্ত বিষয় বিবেচনা করতে হবে।
অভিযোজিত তথ্য পান
Material3 adaptive লাইব্রেরি আপনার অ্যাপটি যে উইন্ডোতে চলছে সে সম্পর্কে তথ্যে সুবিধাজনক অ্যাক্সেস প্রদান করে।
- এই আর্টিফ্যাক্ট এবং এর সংস্করণের জন্য সংস্করণ ক্যাটালগ ফাইলে এন্ট্রি যোগ করুন:
gradle/libs.versions.toml সম্পর্কে
[versions]
material3Adaptive = "1.0.0"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- অ্যাপ মডিউলের বিল্ড ফাইলে, নতুন লাইব্রেরি নির্ভরতা যোগ করুন এবং তারপর একটি গ্র্যাডেল সিঙ্ক করুন:
অ্যাপ/বিল্ড.গ্র্যাডল.কেটিএস
dependencies {
implementation(libs.androidx.material3.adaptive)
}
এখন, যেকোনো কম্পোজেবল স্কোপে, আপনি currentWindowAdaptiveInfo() ব্যবহার করে একটি WindowAdaptiveInfo অবজেক্ট পেতে পারেন যাতে বর্তমান উইন্ডো সাইজ ক্লাস এবং ডিভাইসটি টেবিলটপের মতো ভাঁজযোগ্য অবস্থায় আছে কিনা তার মতো তথ্য থাকে।
আপনি এখন MainActivity তে এটি চেষ্টা করে দেখতে পারেন।
-
ReplyThemeব্লকেরonCreate()তে, উইন্ডো অ্যাডাপ্টিভ তথ্য পান এবং একটিTextcomposable আকারে আকারের ক্লাসগুলি প্রদর্শন করুন। আপনি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(
WindowInsets.safeDrawing.asPaddingValues()
)
)
}
}
}
এখন অ্যাপটি চালালে অ্যাপের কন্টেন্টের উপরে প্রিন্ট করা উইন্ডো সাইজ ক্লাসগুলি দেখাবে। উইন্ডো অ্যাডাপ্টিভ ইনফোতে আর কী কী দেওয়া আছে তা নির্দ্বিধায় অন্বেষণ করুন। পরে আপনি এই Text মুছে ফেলতে পারেন কারণ এটি অ্যাপের কন্টেন্ট কভার করে এবং পরবর্তী ধাপগুলির জন্য এটির প্রয়োজন হবে না।
৪. গতিশীল নেভিগেশন
এখন আপনার অ্যাপটি ব্যবহার করা সহজ করার জন্য ডিভাইসের অবস্থা এবং আকার পরিবর্তনের সাথে সাথে আপনি অ্যাপের নেভিগেশনটি অভিযোজিত করবেন।
ব্যবহারকারীরা যখন ফোন ধরেন, তখন তাদের আঙুলগুলি সাধারণত স্ক্রিনের নীচে থাকে। ব্যবহারকারীরা যখন একটি খোলা ভাঁজযোগ্য ডিভাইস বা ট্যাবলেট ধরেন, তখন তাদের আঙুলগুলি সাধারণত পাশের কাছাকাছি থাকে। আপনার ব্যবহারকারীরা অতিরিক্ত হাতের অবস্থান বা হাতের অবস্থান পরিবর্তন না করেই কোনও অ্যাপের সাথে নেভিগেট করতে বা ইন্টারঅ্যাকশন শুরু করতে সক্ষম হবেন।
আপনার অ্যাপ ডিজাইন করার সময় এবং আপনার লেআউটে ইন্টারেক্টিভ UI উপাদানগুলি কোথায় রাখবেন তা নির্ধারণ করার সময়, স্ক্রিনের বিভিন্ন অঞ্চলের এরগনোমিক প্রভাব বিবেচনা করুন।
- ডিভাইসটি ধরে রাখার সময় কোন কোন জায়গায় পৌঁছানো আরামদায়ক?
- কোন কোন জায়গায় কেবল আঙুল বাড়িয়ে পৌঁছানো যায়, কোনগুলো অসুবিধাজনক হতে পারে?
- ব্যবহারকারীর ডিভাইসটি যেখানে আছে সেখান থেকে কোন এলাকায় পৌঁছানো কঠিন অথবা অনেক দূরে?
ব্যবহারকারীরা প্রথমেই নেভিগেশনের সাথে যোগাযোগ করেন এবং এতে গুরুত্বপূর্ণ ব্যবহারকারীর ভ্রমণের সাথে সম্পর্কিত উচ্চ-গুরুত্বপূর্ণ পদক্ষেপগুলি থাকে, তাই এটি এমন জায়গায় স্থাপন করা উচিত যেখানে পৌঁছানো সবচেয়ে সহজ। ম্যাটেরিয়াল অ্যাডাপ্টিভ লাইব্রেরি ডিভাইসের উইন্ডো আকারের শ্রেণীর উপর নির্ভর করে নেভিগেশন বাস্তবায়নে সহায়তা করার জন্য বেশ কয়েকটি উপাদান সরবরাহ করে।
নীচের নেভিগেশন
কমপ্যাক্ট আকারের জন্য বটম নেভিগেশন উপযুক্ত, কারণ আমরা স্বাভাবিকভাবেই ডিভাইসটিকে এমনভাবে ধরে রাখি যেখানে আমাদের বুড়ো আঙুল সহজেই নীচের সমস্ত নেভিগেশন স্পর্শ বিন্দুতে পৌঁছাতে পারে। যখনই আপনার কাছে কমপ্যাক্ট ডিভাইস আকার থাকে বা কমপ্যাক্ট ভাঁজ করা অবস্থায় ফোল্ডেবল থাকে তখনই এটি ব্যবহার করুন।

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

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

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

গতিশীল নেভিগেশন বাস্তবায়ন করুন
এখন, ডিভাইসের অবস্থা এবং আকার পরিবর্তনের সাথে সাথে আপনি বিভিন্ন ধরণের নেভিগেশনের মধ্যে স্যুইচ করবেন।
বর্তমানে, ডিভাইসের অবস্থা নির্বিশেষে অ্যাপটি সর্বদা স্ক্রিন কন্টেন্টের নীচে একটি NavigationBar দেখায়। পরিবর্তে, আপনি বর্তমান উইন্ডো আকার শ্রেণীর মতো তথ্যের উপর ভিত্তি করে বিভিন্ন নেভিগেশন উপাদানগুলির মধ্যে স্বয়ংক্রিয়ভাবে স্যুইচ করতে ম্যাটেরিয়াল NavigationSuiteScaffold উপাদান ব্যবহার করতে পারেন।
- এই কম্পোনেন্টটি পেতে গ্র্যাডেল ডিপেন্ডেন্সি যোগ করুন ভার্সন ক্যাটালগ এবং অ্যাপের বিল্ড স্ক্রিপ্ট আপডেট করে, তারপর একটি গ্র্যাডেল সিঙ্ক করুন:
gradle/libs.versions.toml সম্পর্কে
[versions]
material3AdaptiveNavSuite = "1.3.0"
[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavSuite" }
অ্যাপ/বিল্ড.গ্র্যাডল.কেটিএস
dependencies {
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
-
ReplyApp.ktএReplyNavigationWrapper()কম্পোজেবল ফাংশনটি খুঁজুন এবং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 মানগুলির কোনওটিতে দেখানো হয়নি। তবে, আপনি একটি ছোট পরিবর্তন করে এটি করতে পারেন।
-
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 ব্যবহার করে এটিকে DP ইউনিটে রূপান্তর করে, এবং তারপর নেভিগেশন UI এর লেআউটের ধরণ নির্ধারণ করতে উইন্ডোর প্রস্থের তুলনা করে। যদি উইন্ডোর প্রস্থ কমপক্ষে 1200.dp হয়, তাহলে এটি NavigationSuiteType.NavigationDrawer ব্যবহার করে। অন্যথায়, এটি ডিফল্ট গণনায় ফিরে যায়।
যখন আপনি আপনার রিসাইজেবল এমুলেটরে অ্যাপটি আবার চালান এবং বিভিন্ন ধরণের চেষ্টা করেন, তখন লক্ষ্য করুন যে যখনই স্ক্রিন কনফিগারেশন পরিবর্তন হয় বা আপনি একটি ফোল্ডিং ডিভাইস উন্মোচন করেন, তখন নেভিগেশনটি সেই আকারের জন্য উপযুক্ত ধরণের হয়ে যায়।

অভিনন্দন, আপনি বিভিন্ন ধরণের উইন্ডোর আকার এবং অবস্থা সমর্থন করার জন্য বিভিন্ন ধরণের নেভিগেশন সম্পর্কে শিখেছেন!
পরবর্তী বিভাগে, আপনি দেখবেন কিভাবে একই তালিকার আইটেম প্রান্ত থেকে প্রান্ত পর্যন্ত প্রসারিত করার পরিবর্তে অবশিষ্ট স্ক্রিন এরিয়ার সুবিধা নেওয়া যায়।
৫. স্ক্রিন স্পেস ব্যবহার
আপনি যদি ছোট ট্যাবলেট, খোলা ডিভাইস, অথবা বড় ট্যাবলেটে অ্যাপটি চালান, তবে অবশিষ্ট স্থান পূরণের জন্য স্ক্রিনটি প্রসারিত হবে। আপনি নিশ্চিত করতে চান যে আপনি আরও তথ্য দেখানোর জন্য সেই স্ক্রিন স্পেসের সুবিধা নিতে পারেন, যেমন এই অ্যাপের জন্য, একই পৃষ্ঠায় ব্যবহারকারীদের ইমেল এবং থ্রেড দেখানো।
উপাদান 3 তিনটি ক্যানোনিকাল লেআউট সংজ্ঞায়িত করে যার প্রতিটিতে কম্প্যাক্ট, মাঝারি এবং প্রসারিত উইন্ডো আকারের ক্লাসের জন্য কনফিগারেশন রয়েছে। List Detail ক্যানোনিকাল লেআউট এই ব্যবহারের ক্ষেত্রে উপযুক্ত, এবং এটি কম্পোজে ListDetailPaneScaffold হিসাবে উপলব্ধ।
- নিম্নলিখিত নির্ভরতা যোগ করে এবং একটি Gradle সিঙ্ক সম্পাদন করে এই উপাদানটি পান:
gradle/libs.versions.toml সম্পর্কে
[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" }
অ্যাপ/বিল্ড.গ্র্যাডল.কেটিএস
dependencies {
implementation(libs.androidx.material3.adaptive.layout)
implementation(libs.androidx.material3.adaptive.navigation)
}
-
ReplyAppContent()কম্পোজেবল ফাংশনটিReplyApp.ktএ খুঁজুন, যা বর্তমানে শুধুমাত্র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 অবস্থা।
-
ReplyHomeViewModel.ktখুলুন এবংReplyHomeUIStateডেটা ক্লাসটি খুঁজুন। নির্বাচিত ইমেলের জন্য একটি বৈশিষ্ট্য যোগ করুন, যার ডিফল্ট মানnull:
উত্তর হোমভিউমডেল.কেটি
data class ReplyHomeUIState(
val emails : List<Email> = emptyList(),
val selectedEmail: Email? = null,
val loading: Boolean = false,
val error: String? = null
)
- একই ফাইলে,
ReplyHomeViewModelএ একটিsetSelectedEmail()ফাংশন রয়েছে যা ব্যবহারকারী যখন একটি তালিকা আইটেমে ট্যাপ করে তখন কল করা হয়। UI অবস্থা অনুলিপি করতে এবং নির্বাচিত ইমেল রেকর্ড করতে এই ফাংশনটি পরিবর্তন করুন:
উত্তর হোমভিউমডেল.কেটি
fun setSelectedEmail(email: Email) {
_uiState.update {
it.copy(selectedEmail = email)
}
}
ব্যবহারকারী কোনও আইটেম ট্যাপ করার পরে নির্বাচিত ইমেলটি null হওয়ার আগে কী ঘটে তা বিবেচনা করার বিষয়। বিস্তারিত ফলকে কী প্রদর্শিত হওয়া উচিত? এই পরিস্থিতি মোকাবেলা করার একাধিক উপায় রয়েছে, যেমন ডিফল্টরূপে তালিকার প্রথম আইটেমটি দেখানো।
- একই ফাইলে,
observeEmails()ফাংশনটি পরিবর্তন করুন। ইমেলের তালিকা লোড হয়ে গেলে, যদি পূর্ববর্তী UI অবস্থায় নির্বাচিত ইমেল না থাকে, তাহলে এটিকে প্রথম আইটেমে সেট করুন:
উত্তর হোমভিউমডেল.কেটি
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()
)
}
}
}
-
ReplyApp.ktএ ফিরে যান এবং নির্বাচিত ইমেলটি ব্যবহার করে, যদি এটি উপলব্ধ থাকে, তাহলে বিস্তারিত প্যানের বিষয়বস্তু পূরণ করুন:
ReplyApp.kt সম্পর্কে
ListDetailPaneScaffold(
// ...
detailPane = {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
)
অ্যাপটি আবার চালান এবং এমুলেটরটিকে ট্যাবলেট আকারে স্যুইচ করুন, এবং দেখুন যে একটি তালিকা আইটেমে ট্যাপ করলে বিস্তারিত প্যানেলের বিষয়বস্তু আপডেট হয়।
যখন উভয় প্যান দৃশ্যমান হয় তখন এটি দুর্দান্ত কাজ করে, কিন্তু যখন উইন্ডোতে কেবল একটি প্যান দেখানোর জন্য জায়গা থাকে, তখন মনে হয় কোনও আইটেম ট্যাপ করলে কিছুই ঘটে না। এমুলেটর ভিউটি একটি ফোনে, অথবা পোর্ট্রেটে থাকা একটি ফোল্ডেবল ডিভাইসে স্যুইচ করার চেষ্টা করুন এবং লক্ষ্য করুন যে কোনও আইটেম ট্যাপ করার পরেও কেবল তালিকা প্যানটি দৃশ্যমান। কারণ নির্বাচিত ইমেলটি আপডেট করা হলেও, ListDetailPaneScaffold এই কনফিগারেশনগুলিতে তালিকা প্যানের উপর ফোকাস রাখছে।
- এটি ঠিক করার জন্য, ল্যাম্বডা
ReplyListPaneযাওয়ার সময় নিম্নলিখিত কোডটি প্রবেশ করান:
ReplyApp.kt সম্পর্কে
ListDetailPaneScaffold(
// ...
listPane = {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
},
// ...
)
এই ল্যাম্বডা পূর্বে তৈরি করা ন্যাভিগেটর ব্যবহার করে যখন কোনও আইটেম ক্লিক করা হয় তখন অতিরিক্ত আচরণ যোগ করে। এটি এই ফাংশনে পাস করা মূল ল্যাম্বডাকে কল করবে এবং তারপর navigator.navigateTo() কে কল করবে যা কোন প্যানটি দেখানো উচিত তা নির্দিষ্ট করবে। স্ক্যাফোল্ডের প্রতিটি প্যানের সাথে একটি ভূমিকা যুক্ত থাকে এবং বিস্তারিত প্যানের জন্য এটি হল ListDetailPaneScaffoldRole.Detail । ছোট উইন্ডোতে, এটি এমন চেহারা দেবে যে অ্যাপটি সামনের দিকে নেভিগেট করেছে।
ব্যবহারকারী যখন বিস্তারিত প্যানেল থেকে ব্যাক বোতাম টিপে তখন কী ঘটে তাও অ্যাপটিকে পরিচালনা করতে হবে এবং এই আচরণটি একটি প্যানেল দৃশ্যমান কিনা তার উপর নির্ভর করে ভিন্ন হবে, নাকি দুটি প্যানেল দৃশ্যমান হবে তার উপর নির্ভর করে।
- নিম্নলিখিত কোডটি যোগ করে ব্যাক নেভিগেশন সমর্থন করুন।
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 তৈরি করে যা যখনই নেভিগেটর পিছনে নেভিগেট করতে পারে তখনই সক্রিয় হয় এবং ল্যাম্বডার ভিতরে navigateBack() কল করে। এছাড়াও, প্যানগুলির মধ্যে রূপান্তরকে আরও মসৃণ করার জন্য, প্রতিটি প্যান একটি AnimatedPane() কম্পোজেবলে মোড়ানো হয়।
বিভিন্ন ধরণের ডিভাইসের জন্য একটি রিসাইজেবল এমুলেটরে অ্যাপটি আবার চালান এবং লক্ষ্য করুন যে যখনই স্ক্রিন কনফিগারেশন পরিবর্তন হয়, অথবা আপনি একটি ফোল্ডিং ডিভাইস উন্মোচন করেন, তখন ডিভাইসের অবস্থার পরিবর্তনের সাথে সাথে নেভিগেশন এবং স্ক্রিনের বিষয়বস্তু গতিশীলভাবে পরিবর্তিত হয়। এছাড়াও তালিকার ফলকে ইমেল ট্যাপ করার চেষ্টা করুন এবং দেখুন লেআউটটি বিভিন্ন স্ক্রিনে কীভাবে আচরণ করে, উভয় ফলক পাশাপাশি দেখায় বা তাদের মধ্যে মসৃণভাবে অ্যানিমেট করে।

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