एक स्क्रॉल दृश्य लेआउट के अंदर एक रैखिक लिंक को भरने के लिए एक सूची एडाप्टर का उपयोग करना


95

मैं एक बहुत ही आम समस्या का सामना कर रहा हूं: मैंने एक गतिविधि की घोषणा की और अब यह पता चला है कि इसके भीतर कुछ वस्तुओं को प्रदर्शित करना चाहिए ScrollView। ऐसा करने का सामान्य तरीका मौजूदा का उपयोग करना होगा ListAdapter, इसे एक ListViewऔर BOOM से कनेक्ट करना होगा जिसमें मेरे पास आइटमों की सूची होगी।

लेकिन आप एक नेस्टेड नहीं डालने चाहिए, ListViewएक में ScrollViewभी Android Lint इसके बारे में शिकायत - यह स्क्रॉल ऊपर शिकंजा के रूप में।

तो यहाँ मेरा सवाल है:

मैं कैसे ListAdapterएक LinearLayoutया कुछ इसी तरह से कनेक्ट करूं ?

मुझे पता है कि यह समाधान बहुत सी वस्तुओं के लिए नहीं होगा, लेकिन मेरी सूचियां बहुत कम हैं (<10 आइटम) इसलिए विचारों की पुन: स्थापना वास्तव में आवश्यक नहीं है। प्रदर्शन के लिहाज से मैं सभी विचारों को सीधे अंदर रख कर जी सकता हूं LinearLayout

एक समाधान जो मैं अपने मौजूदा गतिविधि लेआउट को हेडर व्यू अनुभाग में रखना चाहूंगा ListView। लेकिन यह इस तंत्र को गाली देने जैसा लगता है इसलिए मैं एक क्लीनर समाधान की तलाश में हूं।

विचार?

अद्यतन: सही दिशा में प्रेरित करने के लिए मैं अपनी समस्या दिखाने के लिए एक नमूना लेआउट जोड़ता हूं:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/news_detail_layout"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical"
              android:visibility="visible">


    <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#FFF"
            >

        <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical"
                android:paddingLeft="@dimen/news_detail_layout_side_padding"
                android:paddingRight="@dimen/news_detail_layout_side_padding"
                android:paddingTop="@dimen/news_detail_layout_vertical_padding"
                android:paddingBottom="@dimen/news_detail_layout_vertical_padding"
                >

            <TextView
                    android:id="@+id/news_detail_date"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:gravity="center_horizontal"
                    android:text="LALALA"
                    android:textSize="@dimen/news_detail_date_height"
                    android:textColor="@color/font_black"
                    />

            <Gallery
                    android:id="@+id/news_detail_image"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:paddingTop="5dip"
                    android:paddingBottom="5dip"
                    />

            <TextView
                    android:id="@+id/news_detail_headline"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:gravity="center_horizontal"
                    android:text="Some awesome headline"
                    android:textSize="@dimen/news_detail_headline_height"
                    android:textColor="@color/font_black"
                    android:paddingTop="@dimen/news_detail_headline_paddingTop"
                    android:paddingBottom="@dimen/news_detail_headline_paddingBottom"
                    />

            <TextView
                    android:id="@+id/news_detail_content"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:text="Here comes a lot of text so the scrollview is really needed."
                    android:textSize="@dimen/news_detail_content_height"
                    android:textColor="@color/font_black"
                    />

            <!---
                HERE I NEED THE LIST OF ITEMS PROVIDED BY THE EXISTING ADAPTER. 
                They should be positioned at the end of the content, so making the scrollview smaller is not an option.
            ---->                        

        </LinearLayout>
    </ScrollView>
</LinearLayout>

अद्यतन 2 मैंने इसे समझने में आसान बनाने के लिए शीर्षक बदल दिया (एक डाउनवोट मिला, दोहा!)।


1
क्या तुमने कभी इस समस्या का एक अच्छा साफ समाधान मिल गया? मुझे लगता है कि Google समीक्षाओं के लिए अपने प्ले स्टोर में इसका उपयोग करता है। किसी को पता है कि वे इसे कैसे करते हैं?
ज़ापानोलोगिका

जवाबों:


96

आपको संभवतः अपने आइटम को मैन्युअल रूप से जोड़ना चाहिए LinearLayout:

LinearLayout layout = ... // Your linear layout.
ListAdapter adapter = ... // Your adapter.

final int adapterCount = adapter.getCount();

for (int i = 0; i < adapterCount; i++) {
  View item = adapter.getView(i, null, null);
  layout.addView(item);
}

संपादित करें : जब मैंने लगभग 200 गैर-तुच्छ सूची आइटम प्रदर्शित करने की आवश्यकता की, तो मैंने इस दृष्टिकोण को अस्वीकार कर दिया, यह बहुत धीमा है - नेक्सस 4 को मेरी "सूची" प्रदर्शित करने के लिए लगभग 2 सेकंड की आवश्यकता थी, जो अस्वीकार्य था। इसलिए मैंने हेड के साथ फ़्लो के दृष्टिकोण की ओर रुख किया। यह बहुत तेज़ी से काम करता है क्योंकि उपयोगकर्ता द्वारा स्क्रॉल किए जाने पर सूची दृश्य मांग पर बनाए जाते हैं, न कि उस समय जब दृश्य बनाया जाता है।

फिर से शुरू करें: लेआउट को देखने के लिए मैन्युअल जोड़ कोड (इस प्रकार संभवतः कम चलने वाले भागों और बग) को कोड करना आसान है, लेकिन प्रदर्शन समस्याओं से ग्रस्त है, इसलिए यदि आपको 50 विचार या अधिक पसंद हैं, तो मैं हेडर दृष्टिकोण का उपयोग करने की सलाह देता हूं।

उदाहरण। मूल रूप से गतिविधि (या टुकड़ा) लेआउट इस तरह से कुछ के लिए बदल देती है (अब और नहीं स्क्रॉल की आवश्यकता है):

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/my_top_layout"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>

फिर onCreateView()(मैं एक टुकड़े के साथ एक उदाहरण का उपयोग करूंगा) आपको एक हेडर दृश्य जोड़ने की आवश्यकता है और फिर एक एडेप्टर सेट करें (मैं हेडर संसाधन आईडी मान लेता हूं header_layout):

ListView listView = (ListView) inflater.inflate(R.layout.my_top_layout, container, false);
View header = inflater.inflate(R.layout.header_layout, null);
// Initialize your header here.
listView.addHeaderView(header, null, false);

BaseAdapter adapter = // ... Initialize your adapter.
listView.setAdapter(adapter);

// Just as a bonus - if you want to do something with your list items:
view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // You can just use listView instead of parent casted to ListView.
    if (position >= ((ListView) parent).getHeaderViewsCount()) {
      // Note the usage of getItemAtPosition() instead of adapter's getItem() because
      // the latter does not take into account the header (which has position 0).
      Object obj = parent.getItemAtPosition(position);
      // Do something with your object.
    }
  }
});

हां, यह दूसरा विचार था, लेकिन मुझे यकीन नहीं था ListAdapterऔर ListViewस्क्रीन के पीछे अधिक जादू है जो मैं तब मैन्युअल रूप से नहीं करता।
स्टीफन होथ

बेशक ListView कुछ जादू करता है, तत्वों के बीच कम से कम डिवाइडर, आपको उन्हें मैन्युअल रूप से जोड़ना होगा, मुझे लगता है। ListAdapter (यदि इसे सही तरीके से लागू किया गया है) को और अधिक जादू नहीं करना चाहिए।
स्मोक

2
यह मेरे लिए एक डाउन वोट है। स्मृति किसी को भी जारी करती है? एक कारण है कि हम एडाप्टरों का उपयोग करते हैं ...
केविन पार्कर

1
क्या किसी और को एडॉप्टर की notifyDataSetChangedविधि का उपयोग करके विचारों को अपडेट करने में समस्या है ? यह एक अलग एडॉप्टर पर ठीक काम करता है, जिसे मैंने हुक किया है ListView, लेकिन ऐसा नहीं लगता है कि मैंने जिसको हुक किया है, उसके साथ काम कर रहा हूं LinearLayout
जोकीफे

2
यह एक कारण है जिसके लिए मुझे एंड्रॉइड से नफरत है। मैं नहीं देखता कि आपको जटिल समाधान क्यों लागू करने हैं, या प्रदर्शन समस्याओं से पीड़ित होना चाहिए।
IARI

6

मैं शीर्ष लेख दृश्य समाधान के साथ रहना होगा। इसमें कुछ भी गलत नहीं है। फिलहाल मैं एक ही दृष्टिकोण का उपयोग करके एक गतिविधि को लागू कर रहा हूं।

स्पष्ट रूप से "आइटम भाग" स्थिर से अधिक गतिशील है (आइटम संख्या बनाम बनाम आइटम की गिनती आदि) अन्यथा आप एडेप्टर का उपयोग करने के बारे में बिल्कुल नहीं सोचेंगे। इसलिए जब आपको एडॉप्टर की जरूरत हो तो लिस्ट व्यू का इस्तेमाल करें।

एक समाधान को लागू करना जो एक अडॉप्टर से एक लिनियर लयआउट को पॉप्युलेट करता है एक कस्टम लेआउट के साथ लिस्ट व्यू के निर्माण के अलावा और कुछ नहीं है।

बस मेरे 2 सेंट।


इस दृष्टिकोण का एक दोष यह है कि आपको अपनी पूरी गतिविधि लेआउट (ऊपर देखें) को लेआउट के किसी अन्य टुकड़े में ले जाना होगा ताकि आप इसे लिस्टहैडर व्यू के रूप में संदर्भित कर सकें और एक अन्य लेआउट बना सकें, जिसमें यह भी शामिल है ListView। यकीन नहीं होता कि मुझे यह पैच वर्क पसंद है।
स्टीफन होथ

1
हां, मुझे पता है कि आपका क्या मतलब है, इससे पहले कि मैं इस दृष्टिकोण का उपयोग करना शुरू करूँ, मुझे अपनी गतिविधि लेआउट को कई फ़ाइलों में अलग करने का विचार पसंद नहीं आया। लेकिन जब मैंने देखा कि समग्र लेआउट जैसा दिखता है, तो मुझे उम्मीद थी कि मैं अलगाव के बारे में बुरा नहीं मानूंगा क्योंकि यह केवल दो फाइलों में अलग हो गया है। एक बात जो आपको जरूर पता होनी चाहिए, लिस्ट व्यू में एक खाली दृश्य नहीं होना चाहिए क्योंकि जब कोई सूची आइटम नहीं होता है तो यह आपकी सूची हेडर को छिपा देगा।
फ़्लो

3
इसके अलावा, यदि आप एक पृष्ठ पर कई सूचियाँ रखना चाहते हैं तो यह वास्तव में काम नहीं करता है। क्या किसी के पास एक कस्टम एडाप्टर दृश्य का उदाहरण है जो आइटम को "फ्लैट" सूची में आउटपुट करता है, यानी वह जो स्क्रॉल नहीं करता है।
मुर्तुजा

0

अपना विचार main.xml onCreate पर सेट करें, फिर row.xml से बढ़ें

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="450dp" >

        <ListView
            android:id="@+id/mainListView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_above="@+id/size"
            android:layout_below="@+id/editText1"
            android:gravity="fill_vertical|fill_horizontal"
            android:horizontalSpacing="15dp"
            android:isScrollContainer="true"
            android:numColumns="1"
            android:padding="5dp"
            android:scrollbars="vertical"
            android:smoothScrollbar="true"
            android:stretchMode="columnWidth" >

</ListView>

    <TextView
        android:id="@+id/size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:background="#ff444444"
        android:gravity="center"
        android:text="TextView"
        android:textColor="#D3D3D3"
        android:textStyle="italic" />

    </EditText>

</RelativeLayout> 

row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" 
  android:paddingTop="3dp">

<TextView
  android:id="@+id/rowTextView"
  android:layout_width="0dip"
  android:layout_height="41dp"
  android:layout_margin="4dp"
  android:layout_weight="2.83"
  android:ellipsize="end"
  android:gravity="center_vertical"
  android:lines="1"
  android:text="John Doe"
  android:textColor="@color/color_white"
  android:textSize="23dp" >
</TextView>

</LinearLayout>

मुझे लगता है कि आपको याद आया सवाल समझ में आया। वह LinearLayouts के साथ एक सूची बनाना नहीं चाहते हैं।
फ़्लो

"मैं एक LinearLayout या कुछ समान के लिए एक ListAdapter कैसे कनेक्ट करूं?" बस ओपी ने जो पूछा उसका जवाब देना
fasheikh

2
नहीं, वह एक सूची दृश्य का उपयोग नहीं करना चाहता। वह केवल एक एडेप्टर का उपयोग करना चाहता है और प्रविष्टियों के साथ एक लिनियरलैटआउट को आबाद करने के लिए इसका उपयोग करता है।
फ़्लो

आपके उत्तर के लिए धन्यवाद, लेकिन @ सही है। मैं एक ListView का उपयोग नहीं कर सकता क्योंकि बाहरी लेआउट पहले से ही एक स्क्रॉल दृश्य है। कृपया मेरे पाठ और नमूना लेआउट की जाँच करें।
स्टीफन होथ

उस स्क्रॉल दृश्य की आवश्यकता क्यों है?
फशीख

0

मैं निम्नलिखित कोड का उपयोग करता हूं जो एडाप्टर कार्यक्षमता के साथ ViewGroupऔर को दोहराता है TabLayout। इसके बारे में अच्छी बात यह है कि यदि आप अपनी सूची को बदलते हैं और फिर से बाँधते हैं, तो यह केवल बदली हुई वस्तुओं को प्रभावित करेगा:

उपयोग:

val list = mutableListOf<Person>()
layout.bindChildren(list, { it.personId }, { bindView(it) }, {d, t ->bindView(d, t)})
list.removeAt(0)
list+=newPerson
layout.bindChildren(list, { it.personId }, { bindView(it) }, {d, t ->bindView(d, t)})

के लिए ViewGroups:

fun <Item, Key> ViewGroup.bindChildren(items: List<Item>, id: (Item) -> Key, view: (Item) -> View, bind: (Item, View) -> Unit) {
    val old = children.map { it.tag as Key }.toList().filter { it != null }
    val new = items.map(id)

    val add = new - old
    val remove = old - new
    val keep = new.intersect(old)

    val tagToChildren = children.associateBy { it.tag as Key }
    val idToItem = items.associateBy(id)

    remove.forEach { tagToChildren[it].let { removeView(it) } }
    keep.forEach { bind(idToItem[it]!!, tagToChildren[it]!!) }
    add.forEach { id -> view(idToItem[id]!!).also { it.tag = id }.also { addView(it, items.indexOf(idToItem[id])) } }
}

क्योंकि TabLayoutमेरे पास यह है:

fun <Item, Key> TabLayout.bindTabs(items: List<Item>, toKey: (Item) -> Key, tab: (Item) -> TabLayout.Tab, bind: (Item, TabLayout.Tab) -> Unit) {
    val old = (0 until tabCount).map { getTabAt(it)?.tag as Key }
    val new = items.map(toKey)

    val add = new - old
    val remove = old - new
    val keep = new.intersect(old)

    val tagToChildren = (0 until tabCount).map { getTabAt(it) }.associateBy { it?.tag as Key }
    val idToItem = items.associateBy(toKey)

    remove.forEach { tagToChildren[it].let { removeTab(it) } }
    keep.forEach { bind(idToItem[it]!!, tagToChildren[it]!!) }
    add.forEach { key -> tab(idToItem[key]!!).also { it.tag = key }.also { addTab(it, items.indexOf(idToItem[key])) } }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.