Android:ListView 中的 wrap_content 无效

35

我正在开发 Android 应用。我希望我的列表视图只在水平方向上自适应其内容大小,而不是填满整个宽度。但是,使用 wrap_content 属性并没有实现这个效果。我该怎么做?

5个回答

64
为了在ListView中实现wrap_content高度,我们需要使用自定义的CustomListView,该CustomListView继承了我们本地的ListView。
MyListView.java
public class MyListView extends ListView {

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyListView(Context context) {
        super(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }

}

在您的layout中使用自定义视图,如下所示:

layout.xml

<com.yourpackagename.MyListView
        ...       
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ... />

1
太棒了!当我想在RecyclerView中使用ListView时,这对我很有用。 - Vahid Amiri
4
这个答案很有用,但当ListView在RecyclerView内部时,向上滚动似乎会出现问题。因此,真正的解决方案是重写onMeasure方法。请参见此答案:https://dev59.com/T2Mk5IYBdhLWcg3wxAhM#24186596 - RIscRIpt
1
如果第二行比第一行更大,则无法正常工作。 - Alec von Barnekow
2
高度正常,宽度怎么样?宽度占据了全部长度,如果我将宽度设置为wrapcontent,则无法正常工作。 - rams
运行得非常顺利 - Saad Zahoor
对我不起作用。在我的情况下,父布局是RelativeLayout,layout_height="wrap_content"。 - Talha Ç

39

正如Romain Guy(谷歌工程师负责UI工具包)在他的文章中所说:

通过将宽度设置为wrap_content,您告诉ListView要与其子项中最宽的一项一样宽。因此,ListView必须测量其项目,并获取项目,它必须在适配器上调用getView()。这可能会发生多次,具体取决于布局传递的次数、父布局的行为等。

因此,如果您将ListView的布局宽度或布局高度设置为wrap_content,则ListView将尝试测量附加到它的每个视图-这绝对不是您想要的。

请记住:始终避免为ListViews或GridViews设置wrap_content,有关详细信息,请参见此Google I/O视频,讨论ListView的世界。


9
这条建议似乎并不是通用的。ListView/Adapater组合比人们一开始意识到的更加通用和可扩展,这意味着人们也可能意识不到在使用wrap_content与任意数据集时可能会产生的后果。但这并不意味着没有很多情况下数据集是固定或有限大小的。在这些情况下,使用wrap_content将更多地取决于判断。 - spaaarky21
3
这似乎是Lint应该警告的内容,但它目前没有这样做。 - Someone Somewhere
2
我不知道为什么这个答案被接受:它根本没有回答问题。它还在模仿Romain's Guy的帖子 - 那是关于完全不同的问题:布局被测量的次数 - 并指向一个视频,实际上解释了为什么wrap_content应该工作,至少对于3个列表项,并且对于更复杂的列表“有点用”,但性能成本相当高。 - Rick77
到目前为止,Lint并没有做到这一点。本来可以节省我几个小时的努力! - user1506104

4
可以使用LinearLayout实现。
创建方式如下示例:
public class LinearLayoutAdapter   {
    LinearLayout linearLayout;
    ArrayList<String>  arrayList 
    private View rootView;
    private static LayoutInflater inflater;

    public ChoicesAdapter_(ArrayList<String>  arrayList ,LinearLayout linearLayout)
    {
        this.index =index;
        this.arrayList=arrayList;
        this.linearLayout=linearLayout;
        notifyDataSetChanged();
    }
    private void notifyDataSetChanged() {
        linearLayout.removeAllViews();
        for (int i =0;i<getCount();i++){
            linearLayout.addView(getView(i,null,null));
        }
    }
    public int getCount() {
        return  arrayList.size();
    }
    public Object getItem(int position) {
        return null;
    }
    public long getItemId(int position) {
        return 0;
    }
    public View getView(final int position, View convertView, ViewGroup parent) {
       rootView = inflater.inflate(R.layout.row_list, null);
       TextView  textView = (TextView)rootView.findViewById(R.id.text);    
       textView.setText(arrayList.get(position));
        return rootView;
    }
}

示例MainActivity:

public class MainActivity extends Activity    {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayList<String>  arrayList = new  ArrayList<String>();
        arrayList.add("Accent");
        arrayList.add("Acclaim");
        arrayList.add("Accord");
        arrayList.add("Achieva");
        arrayList.add("Aerio");
        arrayList.add("Aerostar");
        LinearLayout linearLayout = (LinearLayout)findViewById(R.id.linearLayout);
        linearLayoutAdapter= LinearLayoutAdapter(arrayList,linearLayout);
    }
}

XML示例:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:textColor="@color/dark_gray"
    android:background="@color/white"
    android:textSize="20dp"
    android:text=""  />

是的,你可以这样做,但你会失去(或需要实现)listitem视图的回收系统。对于少量项目,它可以正常工作,但如果只有几个项目,您可能不考虑使用listview或适配器。 - Ratata Tata

3
I want my list view to wrap its content horizontally and not to fill all the width. 

在列表视图中,您不能使用“wrap_content”,因为如果您为列表视图提供“wrap_content”属性,只会显示前三个项目(行),其余部分将被忽略。因此,请勿使用“wrap_content”。始终使用“fill_parent”或“match_parent”来设置列表视图。
为了在列表视图上进行高效的设计,您可以查看此视频:World of ListView

2
不要使用fill_parent。它在Android 2.2中已被弃用:http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html#FILL_PARENT - spaaarky21

0

我知道回答这个问题有点晚了。但是在我看来,如果你想让你的ListView具有类似wrap_content的行为,你可以将其开始和结束的边距设置为一些静态值。这在我的情况下起作用了。 如果你担心在各种屏幕尺寸上进行操作,有一个非常有用的库可以处理这种情况。 Scalable DP. 一定要在github上检查一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接