NestedScrollView में RecyclerView को सही तरीके से एम्बेड करना
NestedScrollView के अंदर RecyclerView रखना एक सामान्य पैटर्न है (जैसे: प्रोफाइल स्क्रीन जिसमें हेडर + सूची हो)। मुख्य चुनौती स्क्रॉल संघर्ष और RecyclerView की ऊंचाई मापन है। आधुनिक एंड्रॉइड में setNestedScrollingEnabled(false) या nestedScrollingEnabled="false" XML एट्रिब्यूट से इसे हल किया जाता है।
चरण 1: नया प्रोजेक्ट बनाएं और निर्भरताएं जोड़ें
build.gradle (Module: app):
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.9.0'
// sdp लाइब्रेरी वैकल्पिक (स्केलेबल dp के लिए)
}
चरण 2: मुख्य लेआउट - NestedScrollView में RecyclerView
res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusableInTouchMode="true">
<!-- हेडर सेक्शन (इमेज, प्रोफाइल जानकारी, आदि) -->
<ImageView
android:id="@+id/headerImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/sample_header"
android:contentDescription="हेडर इमेज" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="उत्पाद सूची"
android:textSize="20sp"
android:textStyle="bold" />
<!-- RecyclerView - महत्वपूर्ण: nestedScrollingEnabled=false -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewProducts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:scrollbars="vertical" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
महत्वपूर्ण एट्रिब्यूट्स
- android:nestedScrollingEnabled="false" - RecyclerView को नेस्टेड स्क्रॉलिंग से ऑप्ट-आउट करता है, पैरेंट NestedScrollView को स्क्रॉल नियंत्रण देता है
- android:fillViewport="true" - NestedScrollView को व्यूपोर्ट भरने देता है
- android:layout_height="wrap_content" - RecyclerView अपनी सामग्री के अनुसार विस्तारित होता है
चरण 3: आइटम लेआउट (CardView)
res/layout/item_product.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardElevation="4dp"
app:cardCornerRadius="12dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="12dp"
android:gravity="center">
<ImageView
android:id="@+id/ivProductImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/placeholder"
android:contentDescription="उत्पाद इमेज" />
<TextView
android:id="@+id/tvProductName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="उत्पाद नाम"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvProductPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="₹0"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
चरण 4: मॉडल क्लास
package com.app.sample;
public class Product {
private String name;
private int imageResId;
private double price;
public Product(String name, int imageResId, double price) {
this.name = name;
this.imageResId = imageResId;
this.price = price;
}
public String getName() { return name; }
public int getImageResId() { return imageResId; }
public double getPrice() { return price; }
}
चरण 5: ViewHolder और Adapter
package com.app.sample; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class ProductAdapter extends RecyclerView.Adapter{ private List productList; public ProductAdapter(List productList) { this.productList = productList; } @NonNull @Override public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_product, parent, false); return new ProductViewHolder(view); } @Override public void onBindViewHolder(@NonNull ProductViewHolder holder, int position) { Product product = productList.get(position); holder.ivProduct.setImageResource(product.getImageResId()); holder.tvName.setText(product.getName()); holder.tvPrice.setText(String.format("₹%,.0f", product.getPrice())); } @Override public int getItemCount() { return productList.size(); } static class ProductViewHolder extends RecyclerView.ViewHolder { ImageView ivProduct; TextView tvName, tvPrice; ProductViewHolder(View itemView) { super(itemView); ivProduct = itemView.findViewById(R.id.ivProductImage); tvName = itemView.findViewById(R.id.tvProductName); tvPrice = itemView.findViewById(R.id.tvProductPrice); } } }
चरण 6: MainActivity में सेटअप
package com.app.sample;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerViewProducts);
// GridLayoutManager - 2 कॉलम
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
// प्रदर्शन अनुकूलन
recyclerView.setHasFixedSize(true); // आइटम आकार निश्चित है
recyclerView.setItemViewCacheSize(20); // कैश आकार बढ़ाएं
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
// एडाप्टर सेट करें
ProductAdapter adapter = new ProductAdapter(getSampleProducts());
recyclerView.setAdapter(adapter);
}
private List getSampleProducts() {
List products = new ArrayList<>();
products.add(new Product("iPhone 15", R.drawable.iphone15, 79900));
products.add(new Product("iPhone 15 Pro", R.drawable.iphone15pro, 134900));
products.add(new Product("Samsung S24", R.drawable.s24, 74999));
products.add(new Product("Samsung S24 Ultra", R.drawable.s24ultra, 129999));
products.add(new Product("Pixel 8", R.drawable.pixel8, 75999));
products.add(new Product("Pixel 8 Pro", R.drawable.pixel8pro, 106999));
products.add(new Product("OnePlus 12", R.drawable.oneplus12, 64999));
products.add(new Product("Xiaomi 14", R.drawable.xiaomi14, 54999));
return products;
}
}
प्रदर्शन अनुकूलन टिप्स
| समस्या | समाधान |
|---|---|
| RecyclerView लैग करता है | setHasFixedSize(true) सेट करें यदि आइटम आकार निश्चित है |
| स्क्रॉल जर्की है | setItemViewCacheSize() बढ़ाएं, setDrawingCacheEnabled(true) |
| इमेज लोडिंग धीमी | Glide/Picasso/Coil लाइब्रेरी का उपयोग करें |
| लेआउट पास बहुत अधिक | ConstraintLayout में फ्लैट हायरार्की उपयोग करें |
एडवांस्ड: NestedScrollView के साथ कोऑर्डिनेटर लेआउट
ऐप बार स्क्रॉल प्रभाव के लिए:
<androidx.coordinatorlayout.widget.CoordinatorLayout ...>
<com.google.android.material.appbar.AppBarLayout ...>
<com.google.android.material.appbar.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView ... />
<androidx.appcompat.widget.Toolbar ... />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<RecyclerView ... android:nestedScrollingEnabled="false" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
चरण 7: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.app.sample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.MaterialComponents.DayNight.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
महत्वपूर्ण:android:nestedScrollingEnabled="false"(XML) याrecyclerView.isNestedScrollingEnabled = false(कोड) सेट करना अनिवार्य है। इसके बिना, RecyclerView और NestedScrollView दोनों टच इवेंट्स के लिए प्रतिस्पर्धा करेंगे, जिससे खराब स्क्रॉल अनुभव होगा।