Как показать PopupWindow в специальном месте?

Мне нужно показать PopupWindow под одним Views, показанным на экране.

Как рассчитать координаты нужного View и разместить под ним PopupWindow? Пример кода более чем приветствуется. Спасибо.


person Eugene    schedule 16.09.2011    source источник


Ответы (3)


Найти уже отображаемое представление довольно просто — вот что я использую в своем коде:

public static Rect locateView(View v)
{
    int[] loc_int = new int[2];
    if (v == null) return null;
    try
    {
        v.getLocationOnScreen(loc_int);
    } catch (NullPointerException npe)
    {
        //Happens when the view doesn't exist on screen anymore.
        return null;
    }
    Rect location = new Rect();
    location.left = loc_int[0];
    location.top = loc_int[1];
    location.right = location.left + v.getWidth();
    location.bottom = location.top + v.getHeight();
    return location;
}

Затем вы можете использовать код, аналогичный тому, что предложил Эрнеста, чтобы вставить всплывающее окно в соответствующее место:

popup.showAtLocation(parent, Gravity.TOP|Gravity.LEFT, location.left, location.bottom);

Это покажет всплывающее окно прямо под исходным представлением - хотя нет гарантии, что будет достаточно места для отображения представления.

person zeetoobiker    schedule 21.09.2011
comment
+1 за этот потрясающий и полезный фрагмент кода. Извините, я не могу сделать больше, чем это;) - person S.Thiongane; 19.03.2014
comment
+1 Просто нужно было добавить кое-что, сначала может быть лучше использовать только Gravity.NO_GRAVITY, а затем также, если вы хотите иметь запас, чтобы всплывающее окно не было на краю, вы можете вычесть (например, location.left - 50). Имейте в виду, что при использовании location.right вам необходимо измерить ширину всплывающего окна. Для измерения всплывающего окна перейдите сюда stackoverflow.com /вопросы/15862052/. Окончательный код для окна с полем: location.left - popUpWindowWidth - 50 - person Kim Montano; 19.02.2016
comment
Применяется ли это решение к макетам RTL? Если нет, какие модификации необходимы для работы с конфигурацией справа налево? - person A.B.; 24.01.2017
comment
@ A. B. Вам нужно обработать условие для RTL. Вышеприведенное отражает то же самое для обоих макетов, что означает RTL и LTR. - person arshad shaikh; 09.08.2017
comment
@zeetoobiker Ваше решение работает отлично! Но я использую SwitcherView внутри всплывающего окна. Итак, после переключения вида он меняет положение всплывающего окна. Есть идеи? - person GreenROBO; 16.02.2018

у вас есть getLeft() и getBottom(), чтобы получить точную позицию представления в макете. У вас также есть getWidth() и getHeight(), чтобы узнать точное пространство, занимаемое представлением. Если вы хотите расположить всплывающее окно под представлением.

Вы используете setLeft() и setTop() методы представления для позиционирования нового всплывающего окна.

person Yashwanth Kumar    schedule 16.09.2011
comment
Можете ли вы привести какой-нибудь пример? - person Vijay E; 11.06.2021

Чтобы получить размер основного экрана приложения без таких вещей, как заголовки и панели уведомлений, переопределите следующий метод в классе, создающем рассматриваемый экран (размеры измеряются в пикселях):

@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
}

Чтобы получить нижнюю координату представления, под которым вы хотите отобразить всплывающее окно:

View upperView = ...
int coordinate = upperView.getBottom();

Теперь, пока height - coordinate достаточно велик для вашего всплывающего окна, вы можете просто разместить всплывающее окно следующим образом:

PopupWindow popup = new PopupWindow();

Button button = new Button(this);
button.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        popup.showAtLocation(parent, Gravity.CENTER, 0, coordinate);
    }
});

Здесь showAtLocation() принимает родительский вид в качестве аргумента вместе с гравитацией и смещением местоположения.

person Community    schedule 20.09.2011
comment
Это работает, только если button находится в середине экрана. Даже если бы я установил offset вручную, это не сработает на разных размерах экрана. - person Eugene; 20.09.2011
comment
button может быть везде. - person Eugene; 21.09.2011
comment
Подождите - поэтому предложенное мной решение показывает всплывающее окно чуть ниже вашей кнопки. Если вы поместите кнопку ниже, всплывающее окно также будет отображаться ниже. И поскольку я представляю, что всплывающее окно занимает ширину всего экрана, на самом деле не имеет значения, расположена ли кнопка по центру по горизонтали или нет. Или я что-то здесь упускаю? - person ; 21.09.2011
comment
Хорошо, View.getBottom(). Но была небольшая проблема в коде. Я добавил это изменение в раздел редактирования - person Shaista Naaz; 05.12.2012