Adaptive Layout হল ইন্টারফেস লেআউটের একটি পদ্ধতি যেখানে অ্যাপ্লিকেশন বিভিন্ন ধরনের ডিভাইস এবং স্ক্রিন ওরিয়েন্টেশনের জন্য ভিন্ন ভিন্ন লেআউট ব্যবহার করে। responsive design-এর বিপরীতে, adaptive layout ব্রেকপয়েন্টে পূর্ব-নির্মিত লেআউটের মধ্যে সুইচ করে। এই নিবন্ধটি iOS-এ Size Classes এবং UITraitCollection, Android-এ sw600dp/layout-w600dp কোয়ালিফায়ার এবং ব্যবহারিক উদাহরণগুলি বিশ্লেষণ করে।
মূল পয়েন্ট
Adaptive Layout হল একটি UI কৌশল যেখানে ডেভেলপার প্রতিটি ডিভাইস ধরনের জন্য পৃথক লেআউট তৈরি করে এবং স্ক্রিন বৈশিষ্ট্যের ভিত্তিতে তাদের মধ্যে সুইচ করে। responsive design-এর বিপরীতে যেখানে উপাদানগুলি মসৃণভাবে প্রবাহিত হয়, adaptive layout বিচ্ছিন্ন সুইচিং ব্যবহার করে: ফোন — একটি লেআউট, ট্যাবলেট — আরেকটি, ডেস্কটপ — তৃতীয়টি।
Apple iOS 8 (2014)-এ ইউনিভার্সাল অ্যাপ্লিকেশন (iPhone এবং iPad উভয়েই চলমান বাইনারি) সহ Size Classes চালু করে। Google Android 3.2 (2011)-এ smallestWidth কোয়ালিফায়ার (sw
আধুনিক Apple HIG এবং Google Material Design নির্দেশিকা একমত যে একাধিক স্ক্রিন সাইজ সমর্থন করে এমন অ্যাপ্লিকেশনের জন্য adaptive layout অপরিহার্য। Google Play ট্যাবলেট অভিযোজনের অভাবকে ত্রুটি হিসাবে চিহ্নিত করে। App Store-এর কোনো আনুষ্ঠানিক প্রয়োজনীয়তা নেই, তবে iPad ব্যবহারকারীরা প্রসারিত iPhone অ্যাপের পরিবর্তে নেটিভ অভিজ্ঞতা আশা করেন।
Size Classes হল iOS-এর একটি বৈশিষ্ট্য যা প্রতিটি অক্ষে উপলব্ধ স্থানকে Compact (সংকুচিত) বা Regular (নিয়মিত) হিসাবে সংজ্ঞায়িত করে। UITraitCollection হল একটি iOS সিস্টেম যা ভিউ হায়ারার্কির মাধ্যমে পরিবেশ বৈশিষ্ট্য প্রেরণ করে: আকার, স্ক্রিন স্কেল, force touch ক্ষমতা, কালার গামুট (হালকা/গাঢ়), অ্যাক্সেসিবিলিটি সেটিংস।
| ডিভাইস / ওরিয়েন্টেশন | অনুভূমিক | উল্লম্ব |
|---|---|---|
| iPhone পোর্ট্রেট (সব মডেল) | Compact | Regular |
| iPhone Plus/Pro Max ল্যান্ডস্কেপ | Regular | Compact |
| iPhone SE / mini ল্যান্ডস্কেপ | Compact | Compact |
| iPad পোর্ট্রেট | Regular | Regular |
| iPad ল্যান্ডস্কেপ | Regular | Regular |
| iPad Split View (1/3 স্ক্রিন) | Compact | Regular |
UITraitCollection সিস্টেম দ্বারা গঠিত হয় এবং UIApplication থেকে UIWindow এর মাধ্যমে প্রতিটি UIView-এ প্রেরিত হয়। ওরিয়েন্টেশন বা উইন্ডো সাইজ (Split View) পরিবর্তন হলে সিস্টেম একটি নতুন UITraitCollection তৈরি করে এবং traitCollectionDidChange কল করে। SwiftUI-তে, পরিবর্তনগুলি Environment Values-এর মাধ্যমে ট্র্যাক করা হয় এবং ভিউ স্বয়ংক্রিয়ভাবে পুনরায় আঁকা হয়।
UIKit-এ UITraitCollection-এর মাধ্যমে অভিযোজন trait collection পরিবর্তনে সাবস্ক্রাইব করে এবং লেআউট পুনর্নির্মাণ করে বাস্তবায়িত হয়। নীচের উদাহরণটি একটি কন্ট্রোলার দেখায় যা iPhone-এর জন্য উল্লম্ব স্ট্যাক এবং iPad-এর জন্য স্প্লিট লেআউটের মধ্যে সুইচ করে।
// Size Classes সহ অ্যাডাপ্টিভ কন্ট্রোলার
import UIKit
final class AdaptiveViewController: UIViewController {
private let compactStack = UIStackView()
private let regularStack = UIStackView()
private let sidebar = UIView()
private let content = UIView()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
updateLayout(for: traitCollection)
}
override func traitCollectionDidChange(
_ previousTraitCollection: UITraitCollection?
) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.horizontalSizeClass
!= previousTraitCollection?.horizontalSizeClass {
updateLayout(for: traitCollection)
}
}
private func updateLayout(for traits: UITraitCollection) {
if traits.horizontalSizeClass == .regular {
showRegularLayout() // iPad: সাইডবার + বিষয়বস্তু
} else {
showCompactLayout() // iPhone: ট্যাব বার + পুশ
}
}
private func showRegularLayout() {
view.subviews.forEach { $0.removeFromSuperview() }
regularStack.addArrangedSubview(sidebar)
regularStack.addArrangedSubview(content)
regularStack.frame = view.bounds
regularStack.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(regularStack)
}
private func showCompactLayout() {
view.subviews.forEach { $0.removeFromSuperview() }
compactStack.addArrangedSubview(content)
compactStack.frame = view.bounds
compactStack.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(compactStack)
}
private func setupViews() {
sidebar.backgroundColor = .systemGray6
content.backgroundColor = .systemBackground
compactStack.axis = .vertical
regularStack.axis = .horizontal
}
}traitCollectionDidChange মেথড যেকোনো ট্রেইট পরিবর্তনে কল করা হয়, কিন্তু আমরা শুধু horizontalSizeClass পরীক্ষা করি — লেআউট পরিবর্তনের জন্য সবচেয়ে গুরুত্বপূর্ণ নির্দেশক। iOS 17+-এ পরিবর্তনে সাবস্ক্রাইব না করে প্রতিক্রিয়াশীল আপডেটের জন্য UIViewController.horizontalSizeClass কে গণিত সম্পত্তি হিসাবে ব্যবহার করার পরামর্শ দেওয়া হয়।
Android দুটি প্রধান প্রস্থ কোয়ালিফায়ার প্রদান করে: sw
| কোয়ালিফায়ার | শর্ত | ডিভাইস উদাহরণ |
|---|---|---|
| layout-sw600dp | ন্যূনতম প্রস্থ ≥ 600 dp | iPad (768 dp), Pixel C (900 dp) |
| layout-w600dp | বর্তমান প্রস্থ ≥ 600 dp | Split View-এ iPad (600 dp), ল্যান্ডস্কেপে ফোন |
| layout-land | ল্যান্ডস্কেপ ওরিয়েন্টেশন | যেকোনো ডিভাইস অনুভূমিকভাবে ঘোরানো |
| layout-sw720dp | ন্যূনতম প্রস্থ ≥ 720 dp | iPad Pro (833 dp), Galaxy Tab S9 (800 dp) |
Android-এ রিসোর্স হায়ারার্কি: res/layout/activity_main.xml (ফোন), res/layout-sw600dp/activity_main.xml (7\" ট্যাবলেট), res/layout-w600dp-land/activity_main.xml (ল্যান্ডস্কেপে ফোন)। Android বর্তমান ডিভাইস কনফিগারেশনের সাথে মেলে এমন সবচেয়ে নির্দিষ্ট কোয়ালিফায়ার নির্বাচন করে। যখন কোনো ম্যাচিং ফাইল থাকে না, তখন res/layout/ থেকে বেস রিসোর্স ব্যবহার করা হয়।
আধুনিক Android ডেভেলপমেন্ট সরাসরি রিসোর্স পড়ার পরিবর্তে উইন্ডো সাইজ নির্ধারণ করতে Jetpack WindowManager ব্যবহার করে। এটি বিশেষ করে ফোল্ডেবল ডিভাইসের জন্য গুরুত্বপূর্ণ যেখানে স্ক্রিন সাইজ গতিশীলভাবে পরিবর্তিত হয় (Galaxy Fold 6.2\" থেকে 7.6\" পর্যন্ত খোলে)।
// Jetpack WindowManager-এর মাধ্যমে অভিযোজন
import androidx.window.core.layout.WindowHeightSizeClass
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun AdaptiveScreen() {
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
FlowRow(
verticalAlignment = Arrangement.Top,
horizontalArrangement = when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.EXPANDED -> Arrangement.SpaceEvenly
else -> Arrangement.Start
}
) {
when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.COMPACT -> {
CompactContent()
}
WindowWidthSizeClass.MEDIUM -> {
MediumContent()
}
WindowWidthSizeClass.EXPANDED -> {
ExpandedContent()
}
}
}
}
@Composable
private fun CompactContent() {
Column(modifier = Modifier.padding(16.dp)) {
Text("ফোন", style = MaterialTheme.typography.headlineSmall)
ListContent()
}
}
@Composable
private fun MediumContent() {
Row(modifier = Modifier.padding(24.dp)) {
NavigationRail { ... }
Column { ListContent() }
}
}
@Composable
private fun ExpandedContent() {
Row(modifier = Modifier.padding(32.dp)) {
PermanentNavigationDrawer { ... }
Column {
ListContent()
}
DetailPane()
}
}androidx.window লাইব্রেরির currentWindowAdaptiveInfo() কম্পোনেন্ট যেকোনো ডিভাইসের জন্য ইন্টারফেস অভিযোজিত করে: ফোন, ট্যাবলেট, ফোল্ডেবল, ChromeOS। প্রস্থ ক্লাস: COMPACT (0–600 dp), MEDIUM (600–840 dp), EXPANDED (>840 dp)। উচ্চতা ক্লাস: COMPACT (0–480 dp), MEDIUM (480–900 dp), EXPANDED (>900 dp)।
SwiftUI Size Classes সরাসরি ব্যবহার না করেই অ্যাডাপ্টিভ লেআউটের জন্য বিল্ট-ইন টুল সরবরাহ করে। AnyLayout, ViewThatFits এবং GeometryReader এমন ইন্টারফেস তৈরি করতে দেয় যা স্বয়ংক্রিয়ভাবে উপলব্ধ স্থানের সাথে খাপ খায়।
// AnyLayout এবং ViewThatFits-এর মাধ্যমে SwiftUI অভিযোজন
import SwiftUI
struct AdaptiveGrid: View {
@Environment(\.horizontalSizeClass) private var hSizeClass
var body: some View {
let layout = hSizeClass == .regular
? AnyLayout(HStackLayout())
: AnyLayout(VStackLayout())
layout {
Label("পছন্দসই", systemImage: "star")
Label("সাম্প্রতিক", systemImage: "clock")
Label("সেটিংস", systemImage: "gear")
}
.padding()
}
}
// ViewThatFits — স্বয়ংক্রিয় লেআউট নির্বাচন
struct SmartLayout: View {
var body: some View {
ViewThatFits {
HStack { // অগ্রাধিকার 1: অনুভূমিক
CardView()
CardView()
}
VStack { // যদি না ফিট হয় — উল্লম্ব
CardView()
CardView()
}
}
}
}ViewThatFits একটি শক্তিশালী SwiftUI টুল যা স্বয়ংক্রিয়ভাবে প্রথম চাইল্ড ভিউ নির্বাচন করে যা ক্লিপিং ছাড়াই উপলব্ধ স্থানে ফিট করে। এটি সাধারণ অ্যাডাপ্টিভ সুইচিংয়ের জন্য Size Classes স্পষ্টভাবে পরীক্ষা করার প্রয়োজনীয়তা দূর করে। AnyLayout ভিউ বডিতে if-else ছাড়াই লেআউট টাইপ (HStack/VStack) পরিবর্তন করতে দেয়।
Jetpack Compose অ্যাডাপ্টিভ লেআউটের জন্য WindowSizeClass (Material 3 adaptive লাইব্রেরি থেকে) এবং BoxWithConstraints ব্যবহার করে। XML কোয়ালিফায়ারের বিপরীতে, Compose রানটাইমে উইন্ডো সাইজ নির্ধারণ করে এবং কনফিগারেশন পরিবর্তনে প্রতিক্রিয়াশীলভাবে UI পুনর্গঠন করে।
// BoxWithConstraints-এর মাধ্যমে Jetpack Compose অ্যাডাপ্টিভ
@Composable
fun AdaptiveList(items: List<String>) {
BoxWithConstraints {
val width = maxWidth
if (width >= 600.dp) {
// ট্যাবলেট: দুই কলাম (list-detail)
Row(modifier = Modifier.fillMaxSize()) {
LazyColumn(modifier = Modifier.weight(1f)) {
items(items) { item ->
ListItem(text = item)
}
}
var selected by remember { mutableStateOf(items.first()) }
DetailPanel(item = selected)
.weight(2f)
}
} else {
// ফোন: নেভিগেশন সহ এক কলাম
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items) { item ->
ListItem(text = item, onClick = { navigateToDetail(item) })
}
}
}
}
}
@Composable
fun AdaptiveListMaterial3() {
val windowClass = currentWindowAdaptiveInfo().windowSizeClass
AdaptiveLayout(
layout = windowClass.windowWidthSizeClass
) {
when (windowClass.windowWidthSizeClass) {
WindowWidthSizeClass.COMPACT -> {
ListDetailScaffold(
isDetailOnly = false,
list = { ListPane() },
detail = { DetailPane() }
)
}
else -> {
ListDetailScaffold(
isDetailOnly = false,
list = { ListPane() },
detail = { DetailPane() }
)
}
}
}
}Material 3 Adaptive Layouts প্রস্তুত কম্পোনেন্ট সরবরাহ করে: ListDetailScaffold, SupportingPaneScaffold, NavigationSuiteScaffold। এই কম্পোনেন্টগুলি স্বয়ংক্রিয়ভাবে WindowWidthSizeClass-এর সাথে খাপ খায় — স্ট্যাকড (COMPACT) এবং সাইড-বাই-সাইড (MEDIUM/EXPANDED) এর মধ্যে সুইচ করে। ডেভেলপারকে শুধু একটি প্যাটার্ন বেছে নিতে এবং কন্টেন্ট প্যানেল পাস করতে হবে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
sw600dp (smallestWidth) — ওরিয়েন্টেশন নির্বিশেষে ন্যূনতম স্ক্রিন প্রস্থ। সবসময় 7\"+ ট্যাবলেটে সক্রিয় হয়। w600dp (available width) — বর্তমান ওরিয়েন্টেশন বিবেচনা করে উপলব্ধ প্রস্থ। ল্যান্ডস্কেপে ফোনে সক্রিয় হয় যেখানে প্রস্থ 600 dp-এর বেশি হতে পারে।
UITraitCollection একটি iOS অবজেক্ট যা পরিবেশ বৈশিষ্ট্য ধারণ করে: size classes (অনুভূমিক/উল্লম্ব), ডিসপ্লে স্কেল, force touch ক্ষমতা, ইউজার ইন্টারফেস idiom (iPhone/iPad), কালার গামুট, অ্যাক্সেসিবিলিটি সেটিংস। এটি UIApplication থেকে ভিউ হায়ারার্কির মাধ্যমে প্রেরিত হয় এবং ওরিয়েন্টেশন বা উইন্ডো সাইজ পরিবর্তনে পরিবর্তিত হয়।
Jetpack WindowManager (Android) এবং UIScreen nativeBounds + traitCollection (iOS) ব্যবহার করুন। ফোল্ডেবল ডিভাইসগুলি খোলার সময় Size Class পরিবর্তন করে। ক্যানোনিকাল লেআউট (list-detail, supporting pane) ভিত্তিক আর্কিটেকচার সুপারিশ করা হয় যেখানে Activity পুনরায় চালু না করেই উইন্ডো সাইজ পরিবর্তনের প্রতিক্রিয়াশীল সাবস্ক্রিপশন থাকে।
না। Size Class ভ্যারিয়েশন সহ একটি একক storyboard বা UIKit-এর মাধ্যমে প্রোগ্রামেটিক লেআউট ব্যবহার করুন। SwiftUI-তে storyboards-এর মোটেই প্রয়োজন নেই। iPad-এর জন্য আলাদা storyboards পুনরাবৃত্তি তৈরি করে এবং রক্ষণাবেক্ষণ জটিল করে তোলে — Size Classes-এর মাধ্যমে একটি লেআউট অভিযোজিত করা ভাল।
Canonical layouts হল Google-এর তৈরি অ্যাডাপ্টিভ লেআউট প্যাটার্ন: list-detail (তালিকা + বিস্তারিত), supporting pane (সামগ্রী + অ্যাকশন প্যানেল), feed (কার্ড)। প্রতিটি প্যাটার্ন তিনটি অবস্থা (compact/medium/expanded) সমর্থন করে এবং Material 3 Adaptive লাইব্রেরিতে ListDetailScaffold এবং SupportingPaneScaffold-এর মাধ্যমে বাস্তবায়িত।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন