40

我正在尝试使用 ListPopupWindow 通过一个显示字符串列表ArrayAdapter(最终这将是一个更复杂的自定义适配器)。代码如下。如屏幕截图所示,结果ListPopupWindow似乎内容宽度为零。它显示了正确数量的项目,这些项目仍然是可点击的,并且点击成功会产生一个Toast,所以至少有那么多工作正常。

一个有趣的注释:我可以提供一个以像素为单位的宽度来popup.setWidth(...)代替ListPopupWindow.WRAP_CONTENT它,它会显示一些内容,但这似乎非常不灵活。

如何使ListPopupWindow包装的内容?

测试活动:

public class MainActivity extends Activity {

    private static final String[] STRINGS = {"Option1","Option2","Option3","Option4"};
    private View anchorView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getActionBar().setHomeButtonEnabled(true);
        setContentView(R.layout.activity_main);
        anchorView = findViewById(android.R.id.home);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                showPopup();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void showPopup() {
        ListPopupWindow popup = new ListPopupWindow(this);
        popup.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, STRINGS));
        popup.setAnchorView(anchorView);
        popup.setWidth(ListPopupWindow.WRAP_CONTENT);
        popup.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this, "Clicked item " + position, Toast.LENGTH_SHORT).show();
            }
        });
        popup.show();
    }
}

截屏:

在此处输入图像描述

4

9 回答 9

62

您可以测量适配器内容的宽度:

private int measureContentWidth(ListAdapter listAdapter) {
    ViewGroup mMeasureParent = null;
    int maxWidth = 0;
    View itemView = null;
    int itemType = 0;

    final ListAdapter adapter = listAdapter;
    final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    final int count = adapter.getCount();
    for (int i = 0; i < count; i++) {
        final int positionType = adapter.getItemViewType(i);
        if (positionType != itemType) {
            itemType = positionType;
            itemView = null;
        }

        if (mMeasureParent == null) {
            mMeasureParent = new FrameLayout(mContext);
        }

        itemView = adapter.getView(i, itemView, mMeasureParent);
        itemView.measure(widthMeasureSpec, heightMeasureSpec);

        final int itemWidth = itemView.getMeasuredWidth();

        if (itemWidth > maxWidth) {
            maxWidth = itemWidth;
        }
    }

    return maxWidth;
}

在你的 showPopup() 函数中:

 ArrayAdapter arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, STRINGS);
    popup.setAdapter(arrayAdapter);
    popup.setAnchorView(anchorView);
    popup.setContentWidth(measureContentWidth(arrayAdapter));
于 2014-11-08T07:42:48.217 回答
31

问题在于ListPopupWindow. 我检查了源代码,并使用setContentWidth(ListPopupWindow.WRAP_CONTENT)setWidth(ListPopupWindow.WRAP_CONTENT)使弹出窗口使用其锚视图的宽度。

于 2013-01-24T18:55:45.747 回答
7

我认为最好使用的是 PopupMenu 。例子:

final PopupMenu popupMenu = new PopupMenu(mActivity, v);
popupMenu.getMenu().add("test");
popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

    @Override
    public boolean onMenuItemClick(final MenuItem item) {
        return true;
    }
});
popupMenu.show();
于 2014-04-22T12:06:49.903 回答
5

我只需在您的 dimen.xml 文件中设置一个尺寸为 160dp 左右:

<dimen name="overflow_width">160dp</dimen>

然后使用 getDimensionPixelSize 方法设置弹出窗口宽度以转换为像素:

int width = mContext.getResources().getDimensionPixelSize(R.dimen.overflow_width); 
mListPopupWindow.setWidth(width);

这应该保持尺寸密度独立。

于 2013-09-13T20:05:44.337 回答
3

我相信您的问题在于使用 simple_list_item_1 的 ArrayAdapter。如果您查看该元素的源代码,它具有以下属性

android:layout_width="match_parent"

如果您在此处查看源代码,则可以使用相同的信息创建自己的 new_list_item_1.xml ,但将其更改为android:layout_width="wrap_content"然后在 ArrayAdapter 中使用

于 2013-01-24T18:15:05.863 回答
3

您实际上可以获取anchorView 的父级(因为实际的anchorView 通常是一个按钮)并从那里确定您的宽度。例如:

popup.setWidth(((View)anchor.getParent()).getWidth()/2);

这样你就可以得到一个灵活的宽度。

于 2013-12-26T20:09:19.073 回答
1

另一种解决方案是在布局 xml 中设置 0dp 高度视图以用作锚点。

<View
    android:id="@+id/popup_anchor"
    android:layout_width="140dp"
    android:layout_height="0dp"/>

然后在调用 show() 方法之前的某个时间设置锚视图。

listPopupWindow.setAnchorView(popupAnchor);
listPopupWindow.show();
于 2017-10-04T21:49:28.333 回答
0

以下可以提供帮助;

listPopupWindow.setWidth(400);
listPopupWindow.setHeight(ListPopupWindow.WRAP_CONTENT);
于 2017-06-02T10:51:36.913 回答
0

我对此的态度。

在您的布局中创建一个View用作锚点的布局,使用您的专用宽度和位置(高度 1 dp,宽度如您所愿)(可能是动态的,即使用 ConstraintLayouts)。使其不可见 ( android:visibility=View.INIVISIBLE)。

                <View
                    android:id="@+id/my_anchor"
                    android:layout_height="1dp"
                    android:layout_width="0dp"
                    app:layout_constraintTop_toBottomOf="@id/list_item_order_list_app_compat_image_button_gallery"
                    app:layout_constraintStart_toEndOf="@id/list_item_order_list_material_button_map"
                    app:layout_constraintEnd_toEndOf="parent"
                    android:visibility="invisible"
                    android:layout_marginStart="8dp"
                    android:layout_marginEnd="8dp"
                    />

在您的 , 中引用此视图viewAnchor(即使用绑定):

listPopupWindow.anchorView = binding.myAnchor

于 2021-01-06T12:07:36.510 回答