Отклонение всплывающего окна Android

У меня появляется всплывающее окно, когда я щелкаю элемент в моем списке действий. Проблема в том, что клавиша возврата не закрывает его. Я попытался поймать клавишу возврата в своем действии списка, но он не регистрирует его ... затем я попытался зарегистрировать onkeylistener для представления, которое я передаю в свое всплывающее окно. Нравится:

pop.setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            boolean res=false;
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
                // do something on back.
                Log.e("keydown","back");
                if (pw.isShowing()) {
                    Log.e("keydown","pw showing");
                    pw.dismiss();
                    res = true;
                }
            } else {
                res = false;
            }
            return res;
        }
    });

который передается во всплывающее окно следующим образом:

pw = new PopupWindow(
       pop, 
       240, 
       70, 
       true);

Но и этот слушатель не стреляет. Можешь мне помочь? У меня нет идей :)


person Bostjan    schedule 25.06.2010    source источник
comment
Да, но всплывающее окно содержит изображения, на которые можно нажимать ...   -  person Bostjan    schedule 26.06.2010


Ответы (11)


Это связано с тем, что всплывающее окно не реагирует на события onTouch или onKey, если для него нет фона! = Null. Ознакомьтесь с кодом, который я написал, чтобы помочь с этим. В основном случае вы можете вызвать PopupWindow#setBackgroundDrawable(new BitmapDrawable()), чтобы заставить его действовать так, как вы ожидаете. Вам не понадобится собственный слушатель onKey. Вам также может потребоваться вызвать PopupWindow#setOutsideTouchable(true), если вы хотите, чтобы он уходил, когда пользователь щелкает мышью за пределами границ окна.

Расширенный эзотерический ответ:

Причина, по которой фон не может быть нулевым, заключается в том, что происходит в PopupWindow#preparePopup. Если он обнаруживает background != null, он создает экземпляр PopupViewContainer, вызывает для него setBackgroundDrawable и помещает в него ваше представление содержимого. PopupViewContainer - это, по сути, FrameLayout, который прослушивает события касания и событие KeyEvent.KEYCODE_BACK для закрытия окна. Если background == null, он ничего из этого не делает, а просто использует ваше представление содержимого. В качестве альтернативы зависимости от PopupWindow, чтобы справиться с этим, вы можете расширить свой корень ViewGroup, чтобы он вел себя так, как вы хотите.

person Rich Schuler    schedule 26.06.2010
comment
У меня очень похожая проблема. My CustomView, который передается в PopupWindow, не регистрирует события onKeyDown (), но регистрирует onTouchEvent (). - person znq; 19.10.2010
comment
убедитесь, что вы вызываете setBackgroundDrawable, прежде чем показывать диалог ... мне потребовалось некоторое время, чтобы понять это. - person DallinDyer; 28.09.2011
comment
Могу я спросить, как вы это узнали? Для меня это просто невозможно угадать, так что либо у вас есть доступ к какой-то скрытой документации, либо вы волшебник :) - person Raffaele; 12.10.2012
comment
@Raffaele Android имеет открытый исходный код, а это означает, что вы всегда можете взять код и самостоятельно изучить его, когда вам понадобится дополнительная информация. См. source.android.com. - person Scott W; 17.10.2012
comment
@ScottW, ты правда думаешь, что я об этом не знал? Предоставление исходных текстов - не оправдание написанию плохой документации. Конечно, у меня есть исходники, и я часто использую свой отладчик, чтобы понять, почему что-то работает не так, как ожидалось. Но это явно сбой Android. Даже с источниками и отладчиком сложно понять это, потому что вы не можете вызвать проблему, поскольку окна не реагируют на события касания. - person Raffaele; 17.10.2012
comment
@Raffaele: честно, документация во многих местах оставляет желать лучшего. Я, должно быть, неправильно понял тон вашего вопроса, предполагая, что вы не знали о доступности исходного кода. - person Scott W; 18.10.2012
comment
@ScottW, без проблем: D разработка на Android - это очень весело, но часто процесс разработки не такой простой, как должен. - person Raffaele; 18.10.2012
comment
Привет, вы имеете в виду, что вызов PopupWindow # setOutsideTouchable (true) только закроет всплывающее окно без каких-либо дополнительных действий? Да, я установил возможность рисования фона. - person Sam YC; 08.11.2012
comment
Какого черта, они действительно должны упомянуть В основном случае вы должны вызвать PopupWindow # setBackgroundDrawable (new BitmapDrawable ()) в API, я потратил все утро, пытаясь принять это глупое событие касания, даже если я установил фон содержимого можно получить какой-то цвет. - person Sam YC; 12.11.2012
comment
setBackgroundDrawable удаляет возвышение или тень раскрывающегося списка. Есть ли способы сохранить высоту? - person YellowJ; 28.08.2019

Сделайте следующее, он отлично работает:

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT, true);
pw.setBackgroundDrawable(new BitmapDrawable());
pw.setOutsideTouchable(true);
pw.showAsDropDown(btnSelectWeight);
person Sunil Parmar    schedule 16.11.2011

Для новых проектов лучше использовать

popupWindow.setBackgroundDrawable(new ColorDrawable());

вместо

popupWindow.setBackgroundDrawable(new BitmapDrawable());

поскольку BitmapDrawable устарел. Кроме того, в данном случае это лучше, чем ShapeDrawable. Я заметил, что когда PopupWindow представляет собой прямоугольник с закругленными углами, ShapeDrawable заполняет углы черным цветом.

person CoolMind    schedule 26.08.2014

Очень простое решение - написать pw.setFocusable (true), но, вероятно, вы не захотите этого делать, потому что тогда MapActivity не будет обрабатывать события касания.

Лучшее решение - переопределить клавишу возврата, например, вот так:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    // Override back button
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (pw.isShowing()) {
            pw.dismiss();
            return false;
        }
    }
    return super.onKeyDown(keyCode, event);
} 

Удачи!

person Vanja    schedule 08.11.2010

Для новых поисковиков, поскольку создание new BitmapDrawable сейчас не разрешено (The constructor BitmapDrawable() is deprecated), поэтому вам нужно изменить его на new ShapeDrawable(), чтобы вы изменили:

pw.setBackgroundDrawable(new BitmapDrawable());

Кому:

pw.setBackgroundDrawable(new ShapeDrawable());

И вся работа будет такой:

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT, true);
pw.setOutsideTouchable(true);
pw.setBackgroundDrawable(new ShapeDrawable());
pw.setTouchInterceptor(new OnTouchListener() { // or whatever you want
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            if(event.getAction() == MotionEvent.ACTION_OUTSIDE) // here I want to close the pw when clicking outside it but at all this is just an example of how it works and you can implement the onTouch() or the onKey() you want
            {
               pw.dismiss();
               return true;
            }
            return false;
        }

});
pw.showAtLocation(layout, Gravity.CENTER, 0, 0);
person Muhammed Refaat    schedule 22.05.2014

просто используйте это

mPopupWindow.setBackgroundDrawable(new BitmapDrawable(null,""));

который не является устаревшим. Я бы избегал new ShapeDrawable (), так как он будет отображаться медленно, поскольку он пытается нарисовать форму, когда экран нужно перерисовать.

person j2emanue    schedule 27.05.2014

Я надеюсь это поможет тебе

 pw.setTouchInterceptor(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                pw.dismiss();
            }
            return true;
        }
    });
person Dwivedi Ji    schedule 18.11.2011
comment
Привет, это обязательно, когда мы имеем дело со всплывающим окном? Или pw.setOutsideTouchable (true); достаточно, чтобы закрыть всплывающее окно, когда мы щелкаем за пределами всплывающего окна? - person Sam YC; 08.11.2012
comment
@GMsoF оба должны, посмотрите на мой ответ - person Muhammed Refaat; 22.05.2014

вам нужно добавить setBackgroundDrawable(new BitmapDrawable()) для вашего PopupWindow.

person Carl    schedule 13.03.2015

    private void initPopupWindow() {  
    // TODO Auto-generated method stub  

    View view = getLayoutInflater().inflate(R.layout.main_choice, null);  

    ListView main_menu_listview = (ListView) view.findViewById(R.id.main_menu_listview);  

    ShowMainChoice madapter = new ShowMainChoice(context);
    main_menu_listview.setAdapter(madapter);

    int width = (int)getWindowManager().getDefaultDisplay().getWidth()/2;
    popupWindow = new PopupWindow(view, width,WindowManager.LayoutParams.WRAP_CONTENT);  
    popupWindow.setBackgroundDrawable(new BitmapDrawable());//this is important,如果缺少这句将导致其他任何控件及监听都得不到响应
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);

    main_menu_listview.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
            // TODO Auto-generated method stub

            Log.e("++++++>", arg2+"");

        }
    });
}

Это проблема со всплывающим окном. Удачи.

person AlexChu    schedule 22.08.2013

pw.setBackgroundDrawable(new ColorDrawable());  

должен написать его до setContentView

У меня это работает.

person guptaatul91    schedule 28.12.2018

Если вы ищете сочетание закрытия всплывающего окна и хорошей работы кнопки НАЗАД, то вы можете рассмотреть решение, приведенное ниже.

Принцип решения: все нажатия кнопок рядом с вашим всплывающим окном будут перехватываться, но никакая кнопка НАЗАД перехватываться не будет. Итак, если у вас есть что-то во всплывающем окне, которое выполняет действие, установите индикацию непосредственно перед вызовом dismiss (). В вашем setOnDismissListener () выполните дополнительное действие (например, getActivity (). PopupBackStack ()).

Преимущество этого решения в том, что вы можете создать свой собственный CustomPopupWindow и реализовать эту стратегию. Вы можете скрыть эту реализацию в настраиваемом всплывающем окне.

Шаг 1: добавьте рядом с вашим экземпляром вашего всплывающего окна:

boolean isClickHandled = false; 
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ShapeDrawable());
popupWindow.setTouchInterceptor(new View.OnTouchListener() { // or whatever you want
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        isClickHandled = true;
        return false;
    }
});

Если у вас есть кнопки внутри popupWindow, пусть setOnClickListener.onClick устанавливает isClickHandled = true и dismiss ().

В вашем onDismissListener сделайте что-то вроде:

popupWindow.setOnDismissListener(() -> {
        popupWindow.dismiss();
        if ( !isClickHandled) {
            MainActivity.mainActivity.getSupportFragmentManager().popBackStack();
        }
    });
person tm1701    schedule 23.05.2020