आपके ऐप्लिकेशन की हर स्क्रीन रिस्पॉन्सिव होनी चाहिए और उपलब्ध जगह के हिसाब से अपने-आप अडजस्ट होनी चाहिए.
ConstraintLayout
की मदद से, रिस्पॉन्सिव यूज़र इंटरफ़ेस (यूआई) बनाया जा सकता है. इससे, एक पैनल वाले ऐप्लिकेशन को कई साइज़ में स्केल किया जा सकता है. हालांकि, बड़े डिवाइसों के लिए, लेआउट को कई पैनल में बांटने से फ़ायदा मिल सकता है. उदाहरण के लिए, हो सकता है कि आप किसी स्क्रीन पर, चुने गए आइटम की जानकारी वाली सूची के बगल में आइटम की सूची दिखाना चाहें.
SlidingPaneLayout
घटक, बड़े डिवाइसों और फ़ोल्ड किए जा सकने वाले डिवाइसों पर, एक साथ दो पैनल दिखाने की सुविधा देता है. साथ ही, फ़ोन जैसे छोटे डिवाइसों पर, एक बार में सिर्फ़ एक पैनल दिखाने के लिए अपने-आप अडजस्ट हो जाता है.
किसी डिवाइस के हिसाब से दिशा-निर्देश पाने के लिए, स्क्रीन के साथ काम करने की खास जानकारी देखें.
सेटअप
SlidingPaneLayout
का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन की build.gradle
फ़ाइल में यह डिपेंडेंसी शामिल करें:
ग्रूवी
dependencies { implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0" }
Kotlin
dependencies { implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0") }
एक्सएमएल लेआउट कॉन्फ़िगरेशन
SlidingPaneLayout
, यूज़र इंटरफ़ेस (यूआई) के सबसे ऊपरी लेवल पर इस्तेमाल करने के लिए, हॉरिज़ॉन्टल और दो पैनल वाला लेआउट उपलब्ध कराता है. यह लेआउट, पहले पैनल को कॉन्टेंट की सूची या ब्राउज़र के तौर पर इस्तेमाल करता है. यह दूसरे पैनल में कॉन्टेंट दिखाने के लिए, ज़्यादा जानकारी वाले प्राइमरी व्यू के अधीन होता है.
SlidingPaneLayout
, दोनों पैनल की चौड़ाई का इस्तेमाल करके यह तय करता है कि पैनल को एक साथ दिखाना है या नहीं. उदाहरण के लिए, अगर सूची पैनल का कम से कम साइज़ 200 dp है और ज़्यादा जानकारी वाले पैनल के लिए 400 dp की ज़रूरत है, तो SlidingPaneLayout
दोनों पैनल को एक साथ तब तक दिखाता है, जब तक उसके पास कम से कम 600 dp की चौड़ाई उपलब्ध हो.
अगर चाइल्ड व्यू की कुल चौड़ाई, SlidingPaneLayout
में उपलब्ध चौड़ाई से ज़्यादा हो जाती है, तो चाइल्ड व्यू ओवरलैप हो जाते हैं. इस मामले में, चाइल्ड व्यू SlidingPaneLayout
में उपलब्ध चौड़ाई को भरने के लिए बड़े हो जाते हैं. उपयोगकर्ता, स्क्रीन के किनारे से खींचकर, सबसे ऊपर मौजूद व्यू को स्क्रीन से बाहर कर सकता है.
अगर व्यू ओवरलैप नहीं होते हैं, तो SlidingPaneLayout
चाइल्ड व्यू पर लेआउट पैरामीटर layout_weight
का इस्तेमाल करता है. इससे यह तय किया जा सकता है कि मेज़रमेंट पूरा होने के बाद, बचे हुए स्पेस को कैसे बांटा जाए. यह पैरामीटर सिर्फ़ चौड़ाई के लिए काम आता है.
फ़ोल्ड किए जा सकने वाले ऐसे डिवाइस पर जहां स्क्रीन पर दोनों व्यू को एक साथ दिखाने के लिए जगह होती है, SlidingPaneLayout
दोनों पैनल के साइज़ को अपने-आप अडजस्ट कर देता है, ताकि वे ओवरलैप होने वाले फ़ोल्ड या हिंज के दोनों तरफ़ दिखें. इस मामले में, सेट की गई चौड़ाई को फ़ोल्ड करने की सुविधा के हर तरफ़ मौजूद कम से कम चौड़ाई माना जाता है. अगर कम से कम साइज़ बनाए रखने के लिए ज़रूरी जगह नहीं है, तो SlidingPaneLayout
व्यू को ओवरलैप करने की सुविधा पर वापस स्विच कर देता है.
यहां SlidingPaneLayout
के इस्तेमाल का एक उदाहरण दिया गया है. इसमें बाईं ओर मौजूद पैनल के कॉन्टेंट को दिखाने के लिए, RecyclerView
को बाईं ओर मौजूद पैनल और FragmentContainerView
को पूरी जानकारी वाले प्राइमरी व्यू के तौर पर इस्तेमाल किया गया है:
<!-- two_pane.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">
<!-- The first child view becomes the left pane. When the combined needed
width, expressed using android:layout_width, doesn't fit on-screen at
once, the right pane is permitted to overlap the left. -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_pane"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
<!-- The second child becomes the right (content) pane. In this example,
android:layout_weight is used to expand this detail pane to consume
leftover available space when the entire window is wide enough to fit
the left and right pane.-->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/detail_container"
android:layout_width="300dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:background="#ff333333"
android:name="com.example.SelectAnItemFragment" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
इस उदाहरण में, FragmentContainerView
पर मौजूद android:name
एट्रिब्यूट, ज़्यादा जानकारी वाले पैनल में शुरुआती फ़्रेगमेंट जोड़ता है. इससे यह पक्का होता है कि ऐप्लिकेशन पहली बार लॉन्च होने पर, बड़े स्क्रीन वाले डिवाइसों पर उपयोगकर्ताओं को दाईं ओर खाली पैनल न दिखे.
प्रोग्राम के हिसाब से, ज़्यादा जानकारी वाले पैनल को बदलना
पिछले एक्सएमएल उदाहरण में, RecyclerView
में किसी एलिमेंट पर टैप करने से, ज़्यादा जानकारी वाले पैनल में बदलाव होता है. फ़्रैगमेंट का इस्तेमाल करते समय, इसके लिए एक FragmentTransaction
की ज़रूरत होती है, जो दाएं पैनल की जगह ले लेता है. साथ ही, SlidingPaneLayout
पर open()
को कॉल करके, नए फ़्रैगमेंट पर स्विच करता है:
Kotlin
// A method on the Fragment that owns the SlidingPaneLayout,called by the // adapter when an item is selected. fun openDetails(itemId: Int) { childFragmentManager.commit { setReorderingAllowed(true) replace<ItemFragment>(R.id.detail_container, bundleOf("itemId" to itemId)) // If it's already open and the detail pane is visible, crossfade // between the fragments. if (binding.slidingPaneLayout.isOpen) { setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) } } binding.slidingPaneLayout.open() }
Java
// A method on the Fragment that owns the SlidingPaneLayout, called by the // adapter when an item is selected. void openDetails(int itemId) { Bundle arguments = new Bundle(); arguments.putInt("itemId", itemId); FragmentTransaction ft = getChildFragmentManager().beginTransaction() .setReorderingAllowed(true) .replace(R.id.detail_container, ItemFragment.class, arguments); // If it's already open and the detail pane is visible, crossfade // between the fragments. if (binding.getSlidingPaneLayout().isOpen()) { ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); } ft.commit(); binding.getSlidingPaneLayout().open(); }
यह कोड, FragmentTransaction
पर addToBackStack()
को कॉल नहीं करता. इससे, ज़्यादा जानकारी वाले पैनल में बैक स्टैक बनाने से बचा जा सकता है.
नेविगेशन कॉम्पोनेंट लागू करना
इस पेज पर दिए गए उदाहरणों में, SlidingPaneLayout
का सीधे तौर पर इस्तेमाल किया गया है. साथ ही, आपको फ़्रैगमेंट लेन-देन को मैन्युअल तरीके से मैनेज करना होगा. हालांकि, नेविगेशन कॉम्पोनेंट, AbstractListDetailFragment
की मदद से, पहले से तैयार किए गए दो पैनल वाले लेआउट को लागू करता है. यह एक एपीआई क्लास है, जो सूची और ज़्यादा जानकारी वाले पैनल को मैनेज करने के लिए, SlidingPaneLayout
का इस्तेमाल करती है.
इससे, एक्सएमएल लेआउट कॉन्फ़िगरेशन को आसानी से समझा जा सकता है. SlidingPaneLayout
और दोनों पैनल के बारे में साफ़ तौर पर बताने के बजाय, आपके लेआउट में सिर्फ़ FragmentContainerView
की ज़रूरत होती है, ताकि AbstractListDetailFragment
को लागू किया जा सके:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/two_pane_container"
<!-- The name of your AbstractListDetailFragment implementation.-->
android:name="com.example.testapp.TwoPaneFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!-- The navigation graph for your detail pane.-->
app:navGraph="@navigation/two_pane_navigation" />
</FrameLayout>
अपने सूची पैनल के लिए कस्टम व्यू देने के लिए,
onCreateListPaneView()
और
onListPaneViewCreated()
को लागू करें. ज़्यादा जानकारी वाले पैनल के लिए,
AbstractListDetailFragment
NavHostFragment
का इस्तेमाल करता है.
इसका मतलब है कि आपके पास ऐसा नेविगेशन ग्राफ़ तय करने का विकल्प है जिसमें सिर्फ़ वे डेस्टिनेशन शामिल हों जिन्हें ज़्यादा जानकारी वाले पैनल में दिखाना है. इसके बाद, NavController
का इस्तेमाल करके, ज़्यादा जानकारी वाले पैनल को नेविगेशन ग्राफ़ में मौजूद डेस्टिनेशन के बीच स्विच किया जा सकता है:
Kotlin
fun openDetails(itemId: Int) { val navController = navHostFragment.navController navController.navigate( // Assume the itemId is the android:id of a destination in the graph. itemId, null, NavOptions.Builder() // Pop all destinations off the back stack. .setPopUpTo(navController.graph.startDestination, true) .apply { // If it's already open and the detail pane is visible, // crossfade between the destinations. if (binding.slidingPaneLayout.isOpen) { setEnterAnim(R.animator.nav_default_enter_anim) setExitAnim(R.animator.nav_default_exit_anim) } } .build() ) binding.slidingPaneLayout.open() }
Java
void openDetails(int itemId) { NavController navController = navHostFragment.getNavController(); NavOptions.Builder builder = new NavOptions.Builder() // Pop all destinations off the back stack. .setPopUpTo(navController.getGraph().getStartDestination(), true); // If it's already open and the detail pane is visible, crossfade between // the destinations. if (binding.getSlidingPaneLayout().isOpen()) { builder.setEnterAnim(R.animator.nav_default_enter_anim) .setExitAnim(R.animator.nav_default_exit_anim); } navController.navigate( // Assume the itemId is the android:id of a destination in the graph. itemId, null, builder.build() ); binding.getSlidingPaneLayout().open(); }
ज़्यादा जानकारी वाले पैनल के नेविगेशन ग्राफ़ में मौजूद डेस्टिनेशन, ऐप्लिकेशन के किसी भी बाहरी नेविगेशन ग्राफ़ में नहीं होने चाहिए. हालांकि, ज़्यादा जानकारी वाले पैनल के नेविगेशन ग्राफ़ में मौजूद किसी भी डीप लिंक को उस डेस्टिनेशन से जोड़ा जाना चाहिए जो SlidingPaneLayout
को होस्ट करता है. इससे यह पक्का करने में मदद मिलती है कि बाहरी डीप लिंक पहले SlidingPaneLayout
डेस्टिनेशन पर जाएं और फिर जानकारी वाले पैनल के सही डेस्टिनेशन पर जाएं.
नेविगेशन कॉम्पोनेंट का इस्तेमाल करके, दो पैनल वाले लेआउट को पूरी तरह से लागू करने के लिए, TwoPaneFragment का उदाहरण देखें.
सिस्टम के 'वापस जाएं' बटन के साथ इंटिग्रेट करना
छोटे डिवाइसों पर, सूची और ज़्यादा जानकारी वाले पैनल ओवरलैप हो जाते हैं. इसलिए, पक्का करें कि सिस्टम के 'वापस जाएं' बटन से, उपयोगकर्ता को ज़्यादा जानकारी वाले पैनल से सूची वाले पैनल पर वापस ले जाया जाए. ऐसा करने के लिए, पसंद के मुताबिक बैक नेविगेशन उपलब्ध कराएं और SlidingPaneLayout
की मौजूदा स्थिति से OnBackPressedCallback
को कनेक्ट करें:
Kotlin
class TwoPaneOnBackPressedCallback( private val slidingPaneLayout: SlidingPaneLayout ) : OnBackPressedCallback( // Set the default 'enabled' state to true only if it is slidable, such as // when the panes overlap, and open, such as when the detail pane is // visible. slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen ), SlidingPaneLayout.PanelSlideListener { init { slidingPaneLayout.addPanelSlideListener(this) } override fun handleOnBackPressed() { // Return to the list pane when the system back button is tapped. slidingPaneLayout.closePane() } override fun onPanelSlide(panel: View, slideOffset: Float) { } override fun onPanelOpened(panel: View) { // Intercept the system back button when the detail pane becomes // visible. isEnabled = true } override fun onPanelClosed(panel: View) { // Disable intercepting the system back button when the user returns to // the list pane. isEnabled = false } }
Java
class TwoPaneOnBackPressedCallback extends OnBackPressedCallback implements SlidingPaneLayout.PanelSlideListener { private final SlidingPaneLayout mSlidingPaneLayout; TwoPaneOnBackPressedCallback(@NonNull SlidingPaneLayout slidingPaneLayout) { // Set the default 'enabled' state to true only if it is slideable, such // as when the panes overlap, and open, such as when the detail pane is // visible. super(slidingPaneLayout.isSlideable() && slidingPaneLayout.isOpen()); mSlidingPaneLayout = slidingPaneLayout; slidingPaneLayout.addPanelSlideListener(this); } @Override public void handleOnBackPressed() { // Return to the list pane when the system back button is tapped. mSlidingPaneLayout.closePane(); } @Override public void onPanelSlide(@NonNull View panel, float slideOffset) { } @Override public void onPanelOpened(@NonNull View panel) { // Intercept the system back button when the detail pane becomes // visible. setEnabled(true); } @Override public void onPanelClosed(@NonNull View panel) { // Disable intercepting the system back button when the user returns to // the list pane. setEnabled(false); } }
addCallback()
का इस्तेमाल करके, OnBackPressedDispatcher
में कॉलबैक जोड़ा जा सकता है:
Kotlin
class TwoPaneFragment : Fragment(R.layout.two_pane) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val binding = TwoPaneBinding.bind(view) // Connect the SlidingPaneLayout to the system back button. requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, TwoPaneOnBackPressedCallback(binding.slidingPaneLayout)) // Set up the RecyclerView adapter. } }
Java
class TwoPaneFragment extends Fragment { public TwoPaneFragment() { super(R.layout.two_pane); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TwoPaneBinding binding = TwoPaneBinding.bind(view); // Connect the SlidingPaneLayout to the system back button. requireActivity().getOnBackPressedDispatcher().addCallback( getViewLifecycleOwner(), new TwoPaneOnBackPressedCallback(binding.getSlidingPaneLayout())); // Set up the RecyclerView adapter. } }
लॉक मोड
SlidingPaneLayout
की मदद से, फ़ोन पर सूची और ज़्यादा जानकारी वाले पैनल के बीच स्विच करने के लिए, open()
और close()
को मैन्युअल तरीके से हमेशा कॉल किया जा सकता है. अगर दोनों पैनल दिख रहे हैं और ओवरलैप नहीं हो रहे हैं, तो इन तरीकों का कोई असर नहीं पड़ता.
जब सूची और ज़्यादा जानकारी वाले पैनल ओवरलैप होते हैं, तो उपयोगकर्ता डिफ़ॉल्ट रूप से दोनों दिशाओं में स्वाइप कर सकते हैं. साथ ही, जेस्चर नेविगेशन का इस्तेमाल न करने पर भी, दोनों पैनल के बीच आसानी से स्विच किया जा सकता है. SlidingPaneLayout
के लॉक मोड को सेट करके, स्वाइप करने की दिशा को कंट्रोल किया जा सकता है:
Kotlin
binding.slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
Java
binding.getSlidingPaneLayout().setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED);
ज़्यादा जानें
अलग-अलग फ़ॉर्म फ़ैक्टर के लिए लेआउट डिज़ाइन करने के बारे में ज़्यादा जानने के लिए, यहां दिया गया दस्तावेज़ देखें:
- स्क्रीन के साथ काम करने की सुविधा के बारे में खास जानकारी
- अलग-अलग डिवाइस के नाप या आकार के हिसाब से डिज़ाइन करना