Подтвердить что ты не робот

ListPopupWindow не подчиняется спецификации ширины WRAP_CONTENT

Я пытаюсь использовать 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();
    }
}

скриншот:

enter image description here

4b9b3361

Ответ 1

Проблема заключается в реализации ListPopupWindow. Я проверил исходный код, и используя setContentWidth(ListPopupWindow.WRAP_CONTENT) или setWidth(ListPopupWindow.WRAP_CONTENT), вместо всплывающего окна используется ширина его якорного вида.

Ответ 2

Вы можете измерить ширину содержимого адаптера:

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));

Ответ 3

Я думаю, что лучше всего использовать 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();

Ответ 4

Я бы просто установил измерение в файле dimen.xml на 160dp или около того:

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

Затем установите ширину всплывающего окна, используя метод getDimensionPixelSize для преобразования в пиксели:

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

Это должно поддерживать независимость от плотности размера.

Ответ 5

Я считаю, что ваша проблема связана с вашим ArrayAdapter, используя simple_list_item_1. Если вы посмотрите на исходный код этого элемента, он имеет свойство

android:layout_width="match_parent"

Если вы посмотрите на источник здесь, вы можете создать свой собственный new_list_item_1.xml с той же информацией, но изменив его на android:layout_width="wrap_content", а затем используйте это в своем ArrayAdapter

Ответ 6

Фактически вы можете получить родительский элемент anchorView (поскольку фактическое anchorView обычно является кнопкой) и основывать свою ширину. Например:

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

Таким образом, вы можете получить гибкую ширину.

Ответ 7

listPopupWindow.setWidth(400);

listPopupWindow.setHeight(ListPopupWindow.WRAP_CONTENT);

Ответ 8

Другим решением является установка вида высоты 0dp в вашем макете xml для использования в качестве привязки.

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

затем установите якорный вид когда-нибудь перед вызовом метода show().

listPopupWindow.setAnchorView(popupAnchor);
listPopupWindow.show();