প্রতিক্রিয়াশীল UI এর জন্য নেভিগেশন

ন্যাভিগেশন হল অ্যাপের বিষয়বস্তু গন্তব্য অ্যাক্সেস করতে একটি অ্যাপ্লিকেশনের UI এর সাথে ইন্টারঅ্যাক্ট করার প্রক্রিয়া। Android এর নেভিগেশন নীতিগুলি নির্দেশিকা প্রদান করে যা আপনাকে সামঞ্জস্যপূর্ণ, স্বজ্ঞাত অ্যাপ নেভিগেশন তৈরি করতে সাহায্য করে।

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

জেটপ্যাক নেভিগেশন উপাদান নেভিগেশন নীতিগুলি প্রয়োগ করে এবং প্রতিক্রিয়াশীল UI সহ অ্যাপগুলির বিকাশের সুবিধার্থে ব্যবহার করা যেতে পারে।

চিত্র 1. নেভিগেশন ড্রয়ার, রেল এবং নীচের বার সহ প্রসারিত, মাঝারি এবং কমপ্যাক্ট ডিসপ্লে।

প্রতিক্রিয়াশীল UI নেভিগেশন

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

উইন্ডো সাইজ ক্লাস কয়েকটি আইটেম অনেক আইটেম
কম্প্যাক্ট প্রস্থ নীচের নেভিগেশন বার নেভিগেশন ড্রয়ার (প্রধান প্রান্ত বা নীচে)
মাঝারি প্রস্থ নেভিগেশন রেল নেভিগেশন ড্রয়ার (প্রধান প্রান্ত)
প্রসারিত প্রস্থ নেভিগেশন রেল ক্রমাগত নেভিগেশন ড্রয়ার (প্রধান প্রান্ত)

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

ভিউ

<!-- res/layout/main_activity.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        ... />

    <!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>


<!-- res/layout-w600dp/main_activity.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.navigationrail.NavigationRailView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        ... />

    <!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>


<!-- res/layout-w1240dp/main_activity.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.navigation.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        ... />

    <!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>

রচনা করুন

// This method should be run inside a Composable function.
val widthSizeClass = calculateWindowSizeClass(this).widthSizeClass
// You can get the height of the current window by invoking heightSizeClass instead.

@Composable
fun MyApp(widthSizeClass: WindowWidthSizeClass) {
    // Select a navigation element based on window size.
    when (widthSizeClass) {
        WindowWidthSizeClass.Compact -> { CompactScreen() }
        WindowWidthSizeClass.Medium -> { MediumScreen() }
        WindowWidthSizeClass.Expanded -> { ExpandedScreen() }
    }
}

@Composable
fun CompactScreen() {
    Scaffold(bottomBar = {
                NavigationBar {
                    icons.forEach { item ->
                        NavigationBarItem(
                            selected = isSelected,
                            onClick = { ... },
                            icon = { ... })
                    }
                }
            }
        ) {
        // Other content
    }
}

@Composable
fun MediumScreen() {
    Row(modifier = Modifier.fillMaxSize()) {
        NavigationRail {
            icons.forEach { item ->
                NavigationRailItem(
                    selected = isSelected,
                    onClick = { ... },
                    icon = { ... })
            }
        }
        // Other content
    }
}

@Composable
fun ExpandedScreen() {
    PermanentNavigationDrawer(
        drawerContent = {
            icons.forEach { item ->
                NavigationDrawerItem(
                    icon = { ... },
                    label = { ... },
                    selected = isSelected,
                    onClick = { ... }
                )
            }
        },
        content = {
            // Other content
        }
    )
}

প্রতিক্রিয়াশীল কন্টেন্ট গন্তব্য

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

যখন প্রতিটি স্বতন্ত্র গন্তব্য সুন্দরভাবে পুনরায় আকারের ইভেন্টগুলি পরিচালনা করে, তখন পরিবর্তনগুলি UI-তে বিচ্ছিন্ন হয়। নেভিগেশন সহ অ্যাপের বাকি অবস্থা প্রভাবিত হয় না।

উইন্ডোর আকার পরিবর্তনের পার্শ্ব-প্রতিক্রিয়া হিসাবে নেভিগেশন ঘটতে হবে না। শুধুমাত্র বিভিন্ন উইন্ডো আকার মিটমাট করার জন্য সামগ্রী গন্তব্য তৈরি করবেন না। উদাহরণস্বরূপ, একটি ভাঁজযোগ্য ডিভাইসের বিভিন্ন স্ক্রিনের জন্য বিভিন্ন সামগ্রী গন্তব্য তৈরি করবেন না।

উইন্ডোর আকার পরিবর্তনের পার্শ্ব-প্রতিক্রিয়া হিসাবে নেভিগেট করতে নিম্নলিখিত সমস্যা রয়েছে:

  • পুরানো গন্তব্য (আগের উইন্ডো আকারের জন্য) নতুন গন্তব্যে নেভিগেট করার আগে মুহূর্তের জন্য দৃশ্যমান হতে পারে
  • প্রত্যাবর্তনশীলতা বজায় রাখতে (উদাহরণস্বরূপ, যখন একটি ডিভাইস ভাঁজ করা হয় এবং খোলা হয়), প্রতিটি উইন্ডোর আকারের জন্য নেভিগেশন প্রয়োজন
  • গন্তব্যগুলির মধ্যে অ্যাপ্লিকেশনের অবস্থা বজায় রাখা কঠিন হতে পারে, যেহেতু নেভিগেট ব্যাকস্ট্যাক পপ করার সময় রাজ্যকে ধ্বংস করতে পারে

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

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

বিকল্প লেআউট সহ বিষয়বস্তুর গন্তব্য

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

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

ভিউ

SlidingPaneLayout আপনাকে একটি একক নেভিগেশন গন্তব্য তৈরি করতে সক্ষম করে যা বড় স্ক্রিনে পাশাপাশি দুটি বিষয়বস্তু প্যান প্রদর্শন করে, কিন্তু ফোনের মতো ছোট-স্ক্রীন ডিভাইসে একবারে একটি প্যান দেখায়।

<!-- Single destination for list and detail. -->

<navigation ...>

    <!-- Fragment that implements SlidingPaneLayout. -->
    <fragment
        android:id="@+id/article_two_pane"
        android:name="com.example.app.ListDetailTwoPaneFragment" />

    <!-- Other destinations... -->
</navigation>

SlidingPaneLayout ব্যবহার করে একটি তালিকা-বিশদ বিন্যাস বাস্তবায়নের বিশদ বিবরণের জন্য একটি দুটি ফলক বিন্যাস তৈরি করুন দেখুন।

রচনা করুন

কম্পোজে, একটি তালিকা-বিশদ দৃশ্য একটি একক রুটে বিকল্প কম্পোজেবলকে একত্রিত করে প্রয়োগ করা যেতে পারে যা প্রতিটি আকারের ক্লাসের জন্য উপযুক্ত কম্পোজেবল নির্গত করতে উইন্ডো আকারের ক্লাস ব্যবহার করে।

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

তালিকা-বিশদ দৃশ্য তিনটি কম্পোজেবল নিয়ে গঠিত, উদাহরণস্বরূপ:

/* Displays a list of items. */
@Composable
fun ListOfItems(
    onItemSelected: (String) -> Unit,
) { /*...*/ }

/* Displays the detail for an item. */
@Composable
fun ItemDetail(
    selectedItemId: String? = null,
) { /*...*/ }

/* Displays a list and the detail for an item side by side. */
@Composable
fun ListAndDetail(
    selectedItemId: String? = null,
    onItemSelected: (String) -> Unit,
) {
  Row {
    ListOfItems(onItemSelected = onItemSelected)
    ItemDetail(selectedItemId = selectedItemId)
  }
}

একটি একক নেভিগেশন রুট তালিকা-বিশদ দৃশ্যে অ্যাক্সেস প্রদান করে:

@Composable
fun ListDetailRoute(
    // Indicates that the display size is represented by the expanded window size class.
    isExpandedWindowSize: Boolean = false,
    // Identifies the item selected from the list. If null, a item has not been selected.
    selectedItemId: String?,
) {
  if (isExpandedWindowSize) {
    ListAndDetail(
      selectedItemId = selectedItemId,
      /*...*/
    )
  } else {
    // If the display size cannot accommodate both the list and the item detail,
    // show one of them based on the user's focus.
    if (selectedItemId != null) {
      ItemDetail(
        selectedItemId = selectedItemId,
        /*...*/
      )
    } else {
      ListOfItems(/*...*/)
    }
  }
}

ListDetailRoute (নেভিগেশন গন্তব্য) নির্ধারণ করে যে তিনটি কম্পোজেবলের মধ্যে কোনটি নির্গত হবে: প্রসারিত উইন্ডো আকারের জন্য ListAndDetail ; কম্প্যাক্টের জন্য ListOfItems বা ItemDetail , একটি তালিকা আইটেম নির্বাচন করা হয়েছে কিনা তার উপর নির্ভর করে।

রুটটি একটি NavHost এ অন্তর্ভুক্ত করা হয়েছে, উদাহরণস্বরূপ:

NavHost(navController = navController, startDestination = "listDetailRoute") {
  composable("listDetailRoute") {
    ListDetailRoute(isExpandedWindowSize = isExpandedWindowSize,
                    selectedItemId = selectedItemId)
  }
  /*...*/
}

আপনি আপনার অ্যাপের WindowMetrics পরীক্ষা করে isExpandedWindowSize যুক্তি প্রদান করতে পারেন।

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

class ListDetailViewModel : ViewModel() {

  data class ListDetailUiState(
      val selectedItemId: String? = null,
  )

  private val viewModelState = MutableStateFlow(ListDetailUiState())

  fun onItemSelected(itemId: String) {
    viewModelState.update {
      it.copy(selectedItemId = itemId)
    }
  }
}

val listDetailViewModel = ListDetailViewModel()

@Composable
fun ListDetailRoute(
    isExpandedWindowSize: Boolean = false,
    selectedItemId: String?,
    onItemSelected: (String) -> Unit = { listDetailViewModel.onItemSelected(it) },
) {
  if (isExpandedWindowSize) {
    ListAndDetail(
      selectedItemId = selectedItemId,
      onItemSelected = onItemSelected,
      /*...*/
    )
  } else {
    if (selectedItemId != null) {
      ItemDetail(
        selectedItemId = selectedItemId,
        /*...*/
      )
    } else {
      ListOfItems(
        onItemSelected = onItemSelected,
        /*...*/
      )
    }
  }
}

রুটটিতে একটি কাস্টম BackHandler অন্তর্ভুক্ত থাকে যখন আইটেম বিশদ কম্পোজযোগ্য সমগ্র অ্যাপ উইন্ডোটি দখল করে:

class ListDetailViewModel : ViewModel() {

  data class ListDetailUiState(
      val selectedItemId: String? = null,
  )

  private val viewModelState = MutableStateFlow(ListDetailUiState())

  fun onItemSelected(itemId: String) {
    viewModelState.update {
      it.copy(selectedItemId = itemId)
    }
  }

  fun onItemBackPress() {
    viewModelState.update {
      it.copy(selectedItemId = null)
    }
  }
}

val listDetailViewModel = ListDetailViewModel()

@Composable
fun ListDetailRoute(
    isExpandedWindowSize: Boolean = false,
    selectedItemId: String?,
    onItemSelected: (String) -> Unit = { listDetailViewModel.onItemSelected(it) },
    onItemBackPress: () -> Unit = { listDetailViewModel.onItemBackPress() },
) {
  if (isExpandedWindowSize) {
    ListAndDetail(
      selectedItemId = selectedItemId,
      onItemSelected = onItemSelected,
      /*...*/
    )
  } else {
    if (selectedItemId != null) {
      ItemDetail(
        selectedItemId = selectedItemId,
        /*...*/
      )
      BackHandler {
        onItemBackPress()
      }
    } else {
      ListOfItems(
        onItemSelected = onItemSelected,
        /*...*/
      )
    }
  }
}

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

কম্পোজে সম্পূর্ণ তালিকা-বিশদ দৃশ্য বাস্তবায়নের জন্য, GitHub-এ JetNews নমুনা দেখুন।

একটি নেভিগেশন গ্রাফ

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

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

নেস্টেড নেভিগেশন হোস্ট

আপনার অ্যাপ এমন একটি বিষয়বস্তু গন্তব্য অন্তর্ভুক্ত করতে পারে যার নিজস্ব বিষয়বস্তুর গন্তব্য রয়েছে। উদাহরণস্বরূপ, একটি তালিকা-বিশদ দৃশ্যে, আইটেম বিশদ প্যানে UI উপাদানগুলি অন্তর্ভুক্ত থাকতে পারে যা সামগ্রীতে নেভিগেট করে যা আইটেমের বিবরণ প্রতিস্থাপন করে।

এই ধরনের সাব-নেভিগেশন বাস্তবায়নের জন্য, বিস্তারিত ফলকটি তার নিজস্ব নেভিগেশন গ্রাফ সহ একটি নেস্টেড নেভিগেশন হোস্ট হতে পারে যা বিস্তারিত ফলক থেকে অ্যাক্সেস করা গন্তব্যগুলি নির্দিষ্ট করে:

ভিউ

<!-- layout/two_pane_fragment.xml -->

<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sliding_pane_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list_pane"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"/>

    <!-- Detail pane is a nested navigation host. Its graph is not connected
         to the main graph that contains the two_pane_fragment destination. -->
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/detail_pane"
        android:layout_width="300dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/detail_pane_nav_graph" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>

রচনা করুন

@Composable
fun ItemDetail(selectedItemId: String? = null) {
    val navController = rememberNavController()
    NavHost(navController, "itemSubdetail1") {
        composable("itemSubdetail1") { ItemSubdetail1(...) }
        composable("itemSubdetail2") { ItemSubdetail2(...) }
        composable("itemSubdetail3") { ItemSubdetail3(...) }
    }
}

এটি নেস্টেড নেভিগেশন গ্রাফ থেকে আলাদা কারণ নেস্টেড NavHost এর নেভিগেশন গ্রাফ প্রধান নেভিগেশন গ্রাফের সাথে সংযুক্ত নয়; অর্থাৎ, আপনি একটি গ্রাফের গন্তব্য থেকে অন্য গ্রাফের গন্তব্যে সরাসরি নেভিগেট করতে পারবেন না।

আরও তথ্যের জন্য, নেস্টেড নেভিগেশন গ্রাফ এবং রচনার সাথে নেভিগেটিং দেখুন।

সংরক্ষিত রাষ্ট্র

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

আকার পরিবর্তনগুলি বিপরীত হওয়া উচিত—উদাহরণস্বরূপ, যখন ব্যবহারকারী ডিভাইসটিকে ঘোরান এবং তারপরে এটিকে ঘোরান৷

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

মডেল স্কোপ দেখুন

নেভিগেশন কম্পোনেন্ট ডেভেলপার গাইডে মাইগ্রেট করুন এমন একটি একক-অ্যাক্টিভিটি আর্কিটেকচারের সুপারিশ করে যেখানে গন্তব্যগুলিকে খণ্ড হিসাবে প্রয়োগ করা হয় এবং তাদের ডেটা মডেলগুলি ViewModel ব্যবহার করে প্রয়োগ করা হয়।

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

সবচেয়ে সহজ ক্ষেত্রে, প্রতিটি নেভিগেশন গন্তব্য একটি সম্পূর্ণ বিচ্ছিন্ন UI অবস্থা সহ একটি একক অংশ; এবং তাই, প্রতিটি খণ্ডটি সেই খণ্ডের স্কোপযুক্ত একটি ViewModel পেতে viewModels() সম্পত্তি প্রতিনিধি ব্যবহার করতে পারে।

টুকরোগুলির মধ্যে UI স্থিতি ভাগ করতে, অংশগুলির মধ্যে activityViewModels() কল করে কার্যকলাপের জন্য ViewModel স্কোপ করুন (ক্রিয়াকলাপের সমতুল্য হল viewModels() )। এটি ViewModel দৃষ্টান্ত ভাগ করার জন্য কার্যকলাপ এবং এটির সাথে সংযুক্ত যেকোনো অংশকে অনুমতি দেয়। যাইহোক, একটি একক-অ্যাক্টিভিটি আর্কিটেকচারে, এই ViewModel স্কোপটি কার্যকরভাবে অ্যাপের মতো দীর্ঘস্থায়ী হয়, তাই ViewModel মেমরিতে থাকে এমনকি কোনো টুকরা ব্যবহার না করলেও।

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

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

ব্যাপ্তি সম্পত্তি প্রতিনিধি সাথে ViewModel শেয়ার করতে পারেন
খণ্ড Fragment.viewModels() শুধুমাত্র বর্তমান খণ্ড
কার্যকলাপ Activity.viewModels()

Fragment.activityViewModels()

কার্যকলাপ এবং এটি সংযুক্ত সমস্ত টুকরা
নেভিগেশন গ্রাফ Fragment.navGraphViewModels() একই নেভিগেশন গ্রাফে সমস্ত খণ্ড

মনে রাখবেন যে আপনি যদি একটি নেস্টেড নেভিগেশন হোস্ট ব্যবহার করেন (উপরে দেখুন), সেই হোস্টের গন্তব্যগুলি navGraphViewModels() ব্যবহার করার সময় হোস্টের বাইরের গন্তব্যগুলির সাথে ViewModel s ভাগ করতে পারে না কারণ গ্রাফগুলি সংযুক্ত নয়৷ এই ক্ষেত্রে, আপনি পরিবর্তে কার্যকলাপের সুযোগ ব্যবহার করতে পারেন.

উত্তোলিত রাষ্ট্র

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

উপরে বিকল্প লেআউট সহ বিষয়বস্তু গন্তব্যের রচনা বিভাগে, আমরা ListDetailRoute এ তালিকা-বিশদ দৃশ্য কম্পোজেবলের অবস্থা তুলে ধরেছি যাতে যে কম্পোজেবল প্রদর্শিত হোক না কেন সেই অবস্থাটি সংরক্ষণ করা হয়:

@Composable
fun ListDetailRoute(
    // Indicates that the display size is represented by the expanded window size class.
    isExpandedWindowSize: Boolean = false,
    // Identifies the item selected from the list. If null, a item has not been selected.
    selectedItemId: String?,
) { /*...*/ }

অতিরিক্ত সম্পদ

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}