我面临一个非常普遍的问题:
我列出了一项活动,现在事实证明它应该在ScrollView
中显示一些项目。通常的方法是使用现有的ListAdapter
,将其连接到ListView
和 BOOM 我有我的项目列表。
但是你不应该在ListView
中放置嵌套ScrollView
,因为它会阻止滚动 - 甚至Android Lint也会抱怨它。
所以这是我的问题:
如何将ListAdapter
与LinearLayout
或类似内容相关联?
我知道这个解决方案不会针对很多项目进行扩展,但我的列表非常短(<10项),因此不需要重新查看视图。性能方面我可以直接将所有视图放入LinearLayout
。
我提出的一个解决方案是将现有的活动布局放在ListView
的headerView部分中。但这感觉就像滥用这种机制所以我正在寻找一个更清洁的解决方案。
想法?
更新:为了激发正确的方向,我添加了一个示例布局来显示我的问题:
<?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 我改变了标题以便更容易理解(得到了一个downvote,doh!)。
答案 0 :(得分:94)
您可能只需手动将商品添加到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个非平凡的列表项时,我拒绝了这种方法,它非常慢 - Nexus 4需要大约2秒来显示我的“列表”,这是不可接受的。所以我转向Flo的方法与标题。它的工作速度要快得多,因为列表视图是在用户滚动时按需创建的,而不是在创建视图时创建的。
简历:手动添加布局视图更容易编码(因此可能更少移动部件和错误),但是遇到性能问题,所以如果您有50个或更多视图,我建议使用标题方法。
实施例。基本上,活动(或片段)布局转换为类似的东西(不再需要ScrollView):
<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()
中(我将使用带有片段的示例),您需要添加标题视图,然后设置适配器(我假设标头资源ID为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.
}
}
});
答案 1 :(得分:6)
我会坚持使用标题视图解决方案。这没什么不对。目前,我使用完全相同的方法实施活动。
显然,“项目部分”比静态更动态(不同的项目数与修复项目数量等),否则您根本不会考虑使用适配器。因此,当您需要适配器时,请使用ListView。
实现从适配器填充LinearLayout的解决方案最终只是构建具有自定义布局的ListView。
只需2美分。
答案 2 :(得分: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>
答案 3 :(得分:0)
我使用以下代码来复制sysctl
和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