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 تبدیل کرتے ہیں۔ Activity کو دوبارہ شروع کیے بغیر ونڈو کے سائز کی تبدیلیوں کی رد عمل سبسکرپشن کے ساتھ کینونیکل لے آؤٹ (list-detail, supporting pane) پر مبنی فن تعمیر کی سفارش کی جاتی ہے۔
نہیں۔ 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 ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں