Android 使用ListAdapter在ScrollView布局中填充线性布局
我面临着一个非常普遍的问题: 我展示了一个活动,现在发现它应该在这个Android 使用ListAdapter在ScrollView布局中填充线性布局,android,android-layout,android-arrayadapter,Android,Android Layout,Android Arrayadapter,我面临着一个非常普遍的问题: 我展示了一个活动,现在发现它应该在这个滚动视图中显示一些项目。通常的方法是使用现有的ListAdapter,将其连接到ListView,然后弹出我的项目列表 但是您不应该将嵌套的列表视图放在滚动视图中,因为它会破坏滚动-甚至Android Lint也会抱怨这一点 所以我的问题是: 如何将ListAdapter连接到LinearLayout或类似设备 我知道这个解决方案不能扩展很多项目,但是我的列表很短(
滚动视图中显示一些项目。通常的方法是使用现有的ListAdapter
,将其连接到ListView
,然后弹出我的项目列表
但是您不应该将嵌套的列表视图
放在滚动视图
中,因为它会破坏滚动-甚至Android Lint也会抱怨这一点
所以我的问题是:
如何将ListAdapter
连接到LinearLayout
或类似设备
我知道这个解决方案不能扩展很多项目,但是我的列表很短(<10个项目),所以不需要重用视图。就性能而言,我可以直接将所有视图放置到线性布局中
我提出的一个解决方案是将我现有的活动布局放在列表视图的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我更改了标题以使其更易于理解(获得了否决票,doh!)。在创建时将视图设置为main.xml,然后从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>
您可能应该手动将项目添加到线性布局中
:
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);
}
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.
}
}
});
我会坚持使用标题视图解决方案。没什么问题。目前,我正在使用完全相同的方法实施一项活动
显然,“项目部分”比静态部分更具动态性(不同的项目计数与固定项目计数等),否则您根本不会考虑使用适配器。因此,当您需要适配器时,请使用ListView
实现从适配器填充LinearLayout的解决方案最终只不过是使用自定义布局构建一个ListView
只要我的2美分 我使用以下代码,这些代码通过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)})
对于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])) } }
}
fun TabLayout.bindtab(项目:列表,toKey:(项目)->键,tab:(项目)->TabLayout.tab,bind:(项目,TabLayout.tab)->单位){
val old=(0直到tabCount).map{getTabAt(it)?.tag as Key}
val new=items.map(toKey)
val add=新-旧
val remove=旧-新
val keep=新建。相交(旧)
val tagToChildren=(0到tabCount).map{getTabAt(it)}.associateBy{it?.tagas Key}
val idToItem=项目。关联项(toKey)
remove.forEach{tagToChildren[it]。让{removeTab(it)}
keep.forEach{bind(idToItem[it]!!,tagToChildren[it]!!)}
add.forEach{key->tab(idToItem[key]!!)。还有{it.tag=key}。还有{addTab(it,items.indexOf(idToItem[key]))}
}
我想你不明白这个问题。他不想用LinearLayout填充列表。“如何将ListAdapter连接到LinearLayout或类似的东西?”只是回答OP的问题。他不想使用ListView。他只想使用适配器,并用它来填充带有条目的线性布局。感谢您的回答,但@Flo是正确的。我不能使用ListView,因为外部布局已经是ScrollView。请检查我的文本和示例布局。为什么需要滚动视图?这种方法的一个缺点是,您必须将几乎整个活动布局(见上文)移动到另一个布局中,以便您可以将其作为ListHeaderView引用,并创建另一个布局,其中仅包括ListView
。我不确定我是否喜欢这个补丁。是的,我知道你的意思,在我开始使用这种方法之前,我也不喜欢将我的活动布局分割成多个文件的想法。但是当我看到整体布局看起来和我预期的一样时,我并不介意分离,因为它只分为两个文件。有一点您必须注意,ListView不能有空视图,因为当没有列表项时,这将隐藏您的列表标题。此外,如果您想在一个页面上有多个列表,这实际上是行不通的。有没有人有一个自定义适配器视图的例子,可以将项目输出到一个“平面”列表中,即不滚动的列表。是的,这是我的第二个想法,但我不确定ListAdapter
和ListView
在屏幕后面有更多的魔力,而我不会手动执行。当然,ListView有一些魔力,我想,至少元素之间有分隔符,您必须手动添加它们。ListAdapter(如果实现正确的话)不应该再发挥任何作用了。这是对我的否决票。内存有问题吗?我们使用适配器是有原因的……其他人在使用适配器的notifyDataSetChanged
方法更新视图时有问题吗?这在我连接到列表视图
的另一个适配器上运行良好,但它似乎与我连接到线性布局
的适配器不起作用。这是我讨厌android的原因之一。我不明白你为什么要实施复杂的解决方案,或者遇到性能问题。你有没有找到一个干净的解决方案来解决这个问题?我看到谷歌在他们的游戏商店里用它来评论。有人知道他们是怎么做的吗?
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])) } }
}
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])) } }
}