当对话框中包含 ListView 时,对话框会变得太宽

5

我在包含ListView的对话框宽度上遇到了问题:对话框总是几乎填满屏幕的宽度。以下是问题示例:

过于宽阔的对话框

我需要对话框的宽度与图标匹配。我尝试通过调整对话框样式来解决这个问题,方法在这里这里有描述,但都没有成功。 我认为那些帖子走了错误的轨道(至少对于这个问题来说),因为(1)他们没有解决问题, (2)我可以通过简单地不使用ListView来使对话框大小与期望大小相同。例如,如果我将ListView替换为简单的TextView(详情见下文),则所有内容都会按照期望的大小调整:

紧凑对话框

以下是我用来显示对话框的代码:

private void showDisplayStyleDialog(int id, int choices, int values) {
    final Dialog dlg = new Dialog(this);
    dlg.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dlg.setContentView(R.layout.display_style_dialog);
    final ListView lv = (ListView) dlg.findViewById(android.R.id.list);
    if (lv != null) {
        displayStyleAdapter.setChoices(choices, values);
        lv.setAdapter(displayStyleAdapter);
        lv.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long itemId) {
                dlg.dismiss();
                setDisplayStyle(DisplayStyle
                        .valueOf(displayStyleAdapter.mValues[position]));
            }

        });
    }
    dlg.setCanceledOnTouchOutside(true);
    dlg.show();
}

我还尝试使用AlertDialog.Builder创建对话框,但没有改进。对话框布局(display_style_dialog.xml)如下:

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

    <ListView
        android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/white" >
    </ListView>

</LinearLayout>

适配器从此布局加载每一行:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/holder"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="5dp" >

    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/display_style_image_bg"
        android:contentDescription="@string/cd_display_style" />

</LinearLayout>

使用Android Debug Monitor检查视图层次结构后发现,只有ListView本身是对话框的全宽;每一行都被(如所期望的)调整为与图标宽度相匹配。正是ListView本身强制了宽对话框。如果我将display_style_dialog.xml更改为:

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/test_string"
        android:textColor="@android:color/black"
        android:background="@android:color/white" >
    </TextView>
</LinearLayout>

如果您不对代码或资源进行任何其他更改,则会得到上面显示的紧凑型对话框。据我所知,问题严格来说是由于对话框中存在 ListView 导致的。
我认为我可以通过在 ScrollView 中的 VerticalLayout 中放置许多 ImageView 来解决这个短期问题。不幸的是,图标的排列和数量根据应用程序的内部状态而变化很大,因此这不是一种持续的方法;从长远来看,我确实需要使用 ListView。有关如何解决此问题的任何想法吗?

你应该将高度和宽度从wrap_content改为fill_parent。 - Shani Goriwal
@ShaniGoriwal - 那怎么会有帮助呢?我的整个目标是防止对话框填满窗口。 - Ted Hopp
4个回答

6

首先,抱歉我的英语不好,但我会尽力解释我的观点。

ListView 可以包含任何短或长的数据(例如,字符串)。 因此,如果将 LayoutParams 设置为 wrap_content,就无法知道它有多长。 根据数据,实际数据的宽度可能比屏幕的宽度更长。

因此,如果设置为 wrap_content,它将自动更改为 match_parent/fill_parent(我不确定确切是哪一个)

您还可以在高度上看到这一点。 ListView 不知道应该绘制多少行。 因此,在您的情况下,ListView 的高度将延伸到 Activity 的高度。

Google I/O 2010 中,他们解释了为什么我们不应该在 ListView 上使用 wrap_content。

据我所知,在您的情况下(ListView 的高度为 wrap_content),当 ListView 初始化时,getView() 将被调用与存在的行数一样多次。

因此,我的观点是您可以设置:

  1. 确切的 width_value 给 Dialog,并将 ListView 的宽度设置为 match_parentfill_parent

  2. ListView 的宽度为 Activity 宽度的 x%。


另外,在您的测试中,在 Dialog 中添加 TextView

我们可以通过测量文本来知道确切的宽度值。因此,可以使用 wrap_content


首先,对话框不会扩展到活动的高度,因此WRAP_CONTENT适用于此。其次,行的内容是图像,它们的高度也可以计算,因此我不明白您的逻辑(与使用TextView相比)。但是,感谢您提供GoogleI/O演示文稿的链接;我会查看一下,看看是否有关于发生了什么的解释。 - Ted Hopp
希望你能快速解决这个问题。 :) 顺便说一下,我们使用listView的原因是我们不想一次性测量listview中的所有子视图。 所以,如果你使用listview,这是很自然的。 而且对话框不会扩展到活动的高度,因为列表项只有三个。但是如果你添加更多,对话框将被扩展。 这会导致许多getView调用。 - Steven
我希望这个链接也能帮助到大家。 https://dev59.com/RWw15IYBdhLWcg3wisW- - Steven

1
我认为您可以通过将Listview的layout_width设置为50sp来解决此问题。我的意思是使用固定数字而不是wrap_content。

短期内这可能是一种可能性。我会尝试并观察结果。(我需要使用dp而不是sp;我不显示文本。)然而,我最终需要一个不需要固定宽度的解决方案。 - Ted Hopp
你必须固定listview的宽度,可以使用dimens.xml文件。通过在dimens.xml文件中定义不同的宽度来设置不同屏幕分辨率的宽度。这将是您的listview的长期解决方案。 - arshu

0
我终于成功让它工作了...我子类化了Listview并改变了它的测量方式。似乎Listview本来只会测量第一个子项,所以它使用第一个子项的宽度。我将其更改为搜索Listview的子项以获取最宽的行。
因此,您对话框内容的XML将如下所示:
<?xml version="1.0" encoding="UTF-8"?>

<com.mypackage.myListView
    android:id="@+id/lv"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
 />

而我的列表视图将会是这样的:

public class MyListView extends ListView{

public MyListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    int maxWidth = meathureWidthByChilds() + getPaddingLeft() + getPaddingRight();
    super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY), heightMeasureSpec);     
}


 public int meathureWidthByChilds() {
    int maxWidth = 0;
    View view = null;
    for (int i = 0; i < getAdapter().getCount(); i++) {
        view = getAdapter().getView(i, view, this);
        //this measures the view before its rendered with no constraints from parent
        view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
        if (view.getMeasuredWidth() > maxWidth){
            maxWidth = view.getMeasuredWidth();
        }
    }
    return maxWidth;
 }
}

0
使用RecyclerView代替ListView,这样对话框就不会变得更大了。

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