ScrollView के अंदर ListView का सही उपयोग
⚠️ महत्वपूर्ण चेतावनी: ScrollView के अंदर ListView (या RecyclerView) रखना एक एंटी-पैटर्न है क्योंकि दोनों स्क्रॉल करने योग्य हैं। यह प्रदर्शन समस्याओं, टच इवेंट संघर्ष और माप समस्याओं का कारण बनता है।
बेहतर विकल्प (अनुशंसित):
- NestedScrollView + RecyclerView:
nestedScrollingEnabled = falseके साथ - सिंगल RecyclerView: हेडर/फुटर के लिए एकाधिक व्यू टाइप का उपयोग करें
- ConstraintLayout + Guideline: लचीला लेआउट बिना नेस्टेड स्क्रॉल के
यदि आपको बिल्कुल ListView + ScrollView चाहिए (लीगेसी समर्थन):
चरण 1: नया प्रोजेक्ट बनाएं
एंड्रॉइड स्टूडियो में File → New Project चुनें।
चरण 2: लेआउट (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:fillViewport="true"
android:padding="16dp"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="हेडर सामग्री"
android:textSize="18sp"
android:textStyle="bold"
android:padding="16dp"
android:background="@android:color/holo_blue_light" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="फुटर सामग्री"
android:textSize="18sp"
android:textStyle="bold"
android:padding="16dp"
android:background="@android:color/holo_green_light" />
</LinearLayout>
</ScrollView>
चरण 3: MainActivity.kt
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private val listItems = arrayOf(
"आइटम 1", "आइटम 2", "आइटम 3", "आइटम 4", "आइटम 5",
"आइटम 6", "आइटम 7", "आइटम 8", "आइटम 9", "आइटम 10",
"आइटम 11", "आइटम 12", "आइटम 13", "आइटम 14", "आइटम 15"
)
private lateinit var listView: ListView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp"
listView = findViewById(R.id.listView)
listView.adapter = ArrayAdapter(
this,
android.R.layout.simple_list_item_1,
listItems
)
// ListView की ऊंचाई डायनामिक रूप से सेट करें
setListViewHeightBasedOnItems(listView)
}
// ListView की कुल ऊंचाई की गणना करें और सेट करें
private fun setListViewHeightBasedOnItems(listView: ListView) {
val adapter = listView.adapter ?: return
var totalHeight = 0
val desiredWidth = View.MeasureSpec.makeMeasureSpec(
listView.width,
View.MeasureSpec.AT_MOST
)
for (i in 0 until adapter.count) {
val listItem = adapter.getView(i, null, listView)
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED)
totalHeight += listItem.measuredHeight
}
// डिवाइडर ऊंचाई जोड़ें
val params = listView.layoutParams
params.height = totalHeight + (listView.dividerHeight * (adapter.count - 1))
listView.layoutParams = params
listView.requestLayout()
}
}
चरण 4: ListHelper.kt (यूटिलिटी क्लास)
import android.util.Log
import android.view.View
import android.widget.ListAdapter
import android.widget.ListView
object ListHelper {
fun setListViewHeightBasedOnItems(listView: ListView) {
val adapter: ListAdapter? = listView.adapter ?: return
var totalHeight = 0
val desiredWidth = View.MeasureSpec.makeMeasureSpec(
listView.width,
View.MeasureSpec.AT_MOST
)
for (i in 0 until adapter.count) {
val listItem = adapter.getView(i, null, listView)
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED)
totalHeight += listItem.measuredHeight
}
val params = listView.layoutParams
params.height = totalHeight + (listView.dividerHeight * (adapter.count - 1))
listView.layoutParams = params
listView.requestLayout()
Log.d("ListHelper", "ListView ऊंचाई सेट: $totalHeight px")
}
}
आधुनिक समाधान: NestedScrollView + RecyclerView
<!-- activity_main_modern.xml -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
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="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="हेडर"
android:textSize="20sp"
android:padding="16dp"
android:background="?attr/colorPrimary"
android:textColor="@android:color/white" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
app:layout_constraintTop_toBottomOf="@id/header" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="फुटर"
android:textSize="20sp"
android:padding="16dp"
android:background="?attr/colorSecondary"
android:textColor="@android:color/white" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
// ModernActivity.kt
class ModernActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_modern)
val recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.isNestedScrollingEnabled = false // महत्वपूर्ण!
recyclerView.adapter = MyAdapter(items)
}
}
सर्वोत्तम अभ्यास: एकाधिक व्यू टाइप के साथ सिंगल RecyclerView
sealed class ListItem {
data class Header(val title: String) : ListItem()
data class Content(val text: String) : ListItem()
data class Footer(val text: String) : ListItem()
}
class UnifiedAdapter(private val items: List) :
RecyclerView.Adapter() {
companion object {
const val TYPE_HEADER = 0
const val TYPE_CONTENT = 1
const val TYPE_FOOTER = 2
}
override fun getItemViewType(position: Int) = when (items[position]) {
is ListItem.Header -> TYPE_HEADER
is ListItem.Content -> TYPE_CONTENT
is ListItem.Footer -> TYPE_FOOTER
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) {
TYPE_HEADER -> HeaderHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_header, parent, false))
TYPE_CONTENT -> ContentHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_content, parent, false))
TYPE_FOOTER -> FooterHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_footer, parent, false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[position]) {
is ListItem.Header -> (holder as HeaderHolder).bind(item.title)
is ListItem.Content -> (holder as ContentHolder).bind(item.text)
is ListItem.Footer -> (holder as FooterHolder).bind(item.text)
}
}
override fun getItemCount() = items.size
}