Размытие или размытый фон при активном Android PopupWindow - PullRequest
73 голосов
/ 11 июля 2010

Я хотел бы иметь возможность размыть или затемнить фон, когда я показываю свое всплывающее окно, используя popup.showAtLocation, и убрать / затемнить фон, когда вызывается popup.dismiss.

Я попытался применитьпараметры макета FLAG_BLUR_BEHIND и FLAG_DIM_BEHIND для моей активности, но это, кажется, просто размывает и затемняет фон, как только моё приложение запускается.

Как я могу сделать размытие / затемнение только всплывающими окнами?

Ответы [ 10 ]

101 голосов
/ 23 мая 2012

Вопрос был о классе Popupwindow, но все дали ответы, которые используют класс Dialog. Это бесполезно, если вам нужно использовать класс Popupwindow, потому что Popupwindow не имеет метода getWindow().

Я нашел решение, которое действительно работает с Popupwindow. Для этого требуется только, чтобы корнем XML-файла, который вы используете для фоновой активности, был FrameLayout. Вы можете присвоить элементу Framelayout тег android:foreground. Этот тэг делает то, что указывает на доступный для рисования ресурс, который будет наслоен поверх всего действия (то есть, если Framelayout является корневым элементом в файле xml). Затем вы можете контролировать непрозрачность (setAlpha()) отрисовки переднего плана.

Вы можете использовать любой понравившийся вам ресурс рисования, но если вы просто хотите получить эффект затемнения, создайте XML-файл в папке Drawable с тегом <shape> в качестве корневого.

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid android:color="#000000" />
</shape>

(Подробнее об элементе shape см. http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape). Обратите внимание, что я не указал альфа-значение в цветном теге, который бы делал прорисовываемый элемент прозрачным (например, #ff000000). Причина этого заключается в том, что любое жестко закодированное альфа-значение, по-видимому, переопределяет любые новые альфа-значения, которые мы устанавливаем с помощью setAlpha() в нашем коде, поэтому мы этого не хотим. Однако это означает, что первоначально рисуемый элемент будет непрозрачным (сплошным, непрозрачным). Поэтому нам нужно сделать его прозрачным в методе onCreate() действия.

Вот код элемента xml Framelayout:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mainmenu"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:foreground="@drawable/shape_window_dim" >
...
... your activity's content
...
</FrameLayout>

Вот метод onCreate () в Activity:

public void onCreate( Bundle savedInstanceState)
{
  super.onCreate( savedInstanceState);

  setContentView( R.layout.activity_mainmenu);

  //
  // Your own Activity initialization code
  //

  layout_MainMenu = (FrameLayout) findViewById( R.id.mainmenu);
  layout_MainMenu.getForeground().setAlpha( 0);
}

Наконец, код для уменьшения активности:

layout_MainMenu.getForeground().setAlpha( 220); // dim

layout_MainMenu.getForeground().setAlpha( 0); // restore

Альфа-значения изменяются от 0 (непрозрачный) до 255 (невидимый). Вы должны отменить затемнение, когда закрываете всплывающее окно.

Я не включил код для показа и закрытия всплывающего окна, но вот ссылка на то, как это можно сделать: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/

66 голосов
/ 29 апреля 2015

Поскольку PopupWindow просто добавляет View к WindowManager, вы можете использовать updateViewLayout (View view, ViewGroup.LayoutParams params) для обновления LayoutParams ваших PopupWindow * contentView после вызова show .. ().

Установка флажка окна FLAG_DIM_BEHIND затемнит все за окном. Используйте dimAmount, чтобы контролировать величину затемнения (от 1,0 для полностью непрозрачного до 0,0 для отсутствия затемнения).

Имейте в виду, что если вы установите фон для вашего PopupWindow, он поместит ваш contentView в контейнер, что означает, что вам нужно обновить его родительский элемент.

С фоном:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(background);
popup.showAsDropDown(anchor);

View container = (View) popup.getContentView().getParent();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(container, p);

без фона:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(null);
popup.showAsDropDown(anchor);

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) contentView.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(contentView, p);

Обновление "Зефир":

В M PopupWindow оборачивает contentView внутри FrameLayout, называемого mDecorView. Если вы покопаетесь в источнике PopupWindow, то обнаружите что-то вроде createDecorView(View contentView). Основная цель mDecorView - обрабатывать диспетчеризацию событий и переходы содержимого, которые являются новыми для M. Это означает, что нам нужно добавить еще один .getParent () для доступа контейнер.

С фоном, который потребует изменения что-то вроде:

View container = (View) popup.getContentView().getParent().getParent();

Лучшая альтернатива для API 18 +

Менее хакерское решение с использованием ViewGroupOverlay:

1) Возьмите нужный корневой макет

ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();

2) Звоните applyDim(root, 0.5f); или clearDim()

public static void applyDim(@NonNull ViewGroup parent, float dimAmount){
    Drawable dim = new ColorDrawable(Color.BLACK);
    dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
    dim.setAlpha((int) (255 * dimAmount));

    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.add(dim);
}

public static void clearDim(@NonNull ViewGroup parent) {
    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.clear();
}
28 голосов
/ 08 апреля 2013

В вашем XML-файле добавьте что-то вроде этого с шириной и высотой как 'match_parent'.

<RelativeLayout
        android:id="@+id/bac_dim_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#C0000000"
        android:visibility="gone" >
</RelativeLayout>

В вашей деятельности создается

//setting background dim when showing popup
back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);

Наконец, сделайте видимым, когда вы показываете всплывающее окно, и сделайте его видимым исчезнувшим при выходе из всплывающего окна.

back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);
11 голосов
/ 26 марта 2013

Еще один прием - использовать 2 всплывающих окна вместо одного.1-е всплывающее окно будет просто фиктивным видом с полупрозрачным фоном, который обеспечивает эффект затемнения.Второе всплывающее окно - это ваше предполагаемое всплывающее окно.

Последовательность при создании всплывающих окон: Показать всплывающее окно-пустышку 1-го и затем намеченное всплывающее окно.

Последовательность при уничтожении: Отклонитьпредполагаемое всплывающее окно, а затем пустое всплывающее окно.

Лучший способ связать эти два - добавить OnDismissListener и переопределить метод onDismiss() предполагаемогочтобы уменьшить всплывающее окно-заглушку из их.

Код для всплывающего окна-заглушки:

fadepopup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:id="@+id/fadePopup"
    android:background="#AA000000">
</LinearLayout>

Показать всплывающее окно исчезновения, чтобы затемнить фон

private PopupWindow dimBackground() {

    LayoutInflater inflater = (LayoutInflater) EPGGRIDActivity.this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View layout = inflater.inflate(R.layout.fadepopup,
            (ViewGroup) findViewById(R.id.fadePopup));
    PopupWindow fadePopup = new PopupWindow(layout, windowWidth, windowHeight, false);
    fadePopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
    return fadePopup;
}
5 голосов
/ 17 февраля 2012

Я нашел решение для этого

Создайте собственный прозрачный диалог, и внутри этого диалога откройте всплывающее окно:

dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);
emptyDialog = LayoutInflater.from(context).inflate(R.layout.empty, null);

/* blur background*/
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();  
lp.dimAmount=0.0f;  
dialog.getWindow().setAttributes(lp);  
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
dialog.setContentView(emptyDialog);
dialog.setCanceledOnTouchOutside(true);
dialog.setOnShowListener(new OnShowListener()
{
    @Override
    public void onShow(DialogInterface dialogIx)
    {
        mQuickAction.show(emptyDialog); //open the PopupWindow here
    }
});
dialog.show();

xml для диалога (R.layout.empty):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent" android:layout_width="match_parent"
     style="@android:style/Theme.Translucent.NoTitleBar" />

теперь вы хотите закрыть диалоговое окно, когда всплывающее окно закрывается. так

mQuickAction.setOnDismissListener(new OnDismissListener()
{
    @Override
    public void onDismiss()
    {
        if(dialog!=null)
        {
            dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes
            dialog = null;
        }
    }
});

Примечание. Я использовал плагин NewQuickAction для создания PopupWindow. Это также можно сделать на родном Popup Windows

0 голосов
/ 13 мая 2019

Может быть, вам поможет это репо: BasePopup

Это мое репо, которое используется для решения различных задач PopupWindow.

В случае использованиябиблиотека, если вам нужно размыть фон, просто позвоните setBlurBackgroundEnable(true).

См. вики для более подробной информации. (Язык в zh-cn)

BasePopup: wiki

0 голосов
/ 31 января 2019

Для меня что-то вроде ответа Абдельхака Муааму работает, протестировано на уровне API 16 и 27.

Вместо использования popupWindow.getContentView().getParent() и преобразования результата в View (что приводит к сбою на уровне API 16, потому что там возвращается объект ViewRootImpl, который не является экземпляром View), я просто использую .getRootView() который уже возвращает представление, поэтому там не требуется кастинг.

Надеюсь, это кому-нибудь поможет:)

Завершите рабочий пример, скремблированный с другими сообщениями stackoverflow, просто скопируйте и вставьте его, например, в прослушиватель onClick кнопки:

// inflate the layout of the popup window
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
if(inflater == null) {
    return;
}
//View popupView = inflater.inflate(R.layout.my_popup_layout, null); // this version gives a warning cause it doesn't like null as argument for the viewRoot, c.f. https://stackoverflow.com/questions/24832497 and https://stackoverflow.com/questions/26404951
View popupView = View.inflate(MyParentActivity.this, R.layout.my_popup_layout, null);

// create the popup window
final PopupWindow popupWindow = new PopupWindow(popupView,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        true // lets taps outside the popup also dismiss it
        );

// do something with the stuff in your popup layout, e.g.:
//((TextView)popupView.findViewById(R.id.textview_popup_helloworld))
//      .setText("hello stackoverflow");

// dismiss the popup window when touched
popupView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            popupWindow.dismiss();
            return true;
        }
});

// show the popup window
// which view you pass in doesn't matter, it is only used for the window token
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
//popupWindow.setOutsideTouchable(false); // doesn't seem to change anything for me

View container = popupWindow.getContentView().getRootView();
if(container != null) {
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams p = (WindowManager.LayoutParams)container.getLayoutParams();
    p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
    p.dimAmount = 0.3f;
    if(wm != null) {
        wm.updateViewLayout(container, p);
    }
}
0 голосов
/ 31 декабря 2018

хорошо, так что я следую за ответом от uhmdown для затемнения фоновой активности, когда всплывающее окно открыто.Но это создает проблему для меня.это было диммерное действие и включало всплывающее окно (означает, что диммированный черный слой как на активности, так и во всплывающем окне, его нельзя разделить).

, поэтому я попробовал этот способ,

создать *Файл 1007 * dimming_black.xml для эффекта затемнения,

 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#33000000" />
</shape>

И добавление в качестве background в FrameLayout в качестве корневого тега xml, также поместите мои другие элементы управления в LinearLayout, например, layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/ff_drawable_black">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="bottom"
        android:background="@color/white">

        // other codes...
    </LinearLayout>

</FrameLayout>

наконец я показываю всплывающее окно на моем MainActivity с некоторыми дополнительными параметрами, установленными как показано ниже.

           //instantiate popup window
            popupWindow = new PopupWindow(viewPopup, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, true);

            //display the popup window
            popupWindow.showAtLocation(layout_ff, Gravity.BOTTOM, 0, 0);

Результат: enter image description here

это работает для меня, также решена проблема, как прокомментировано BaDo ,С этим Actionbar также может быть затемнено.

Ps Я не говорю, что uhmdown's неправильно.Я научился формировать его ответ и пытаться развиваться для моей проблемы.Я также запутался, является ли это хорошим способом или нет.

Любые предложения также приветствуются, также извините за мой плохой английский.

0 голосов
/ 19 мая 2017

Этот код работает

        pwindo = new PopupWindow(layout, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
        pwindo.setOutsideTouchable(false);

        View container = (View) pwindo.getContentView().getParent();
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
        p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
        p.dimAmount = 0.3f;
        wm.updateViewLayout(container, p);
0 голосов
/ 11 июля 2010

Вы можете использовать android:theme="@android:style/Theme.Dialog" для этого. Создайте активность и в своем AndroidManifest.xml определите активность как:

    <activity android:name=".activities.YourActivity"
              android:label="@string/your_activity_label"
              android:theme="@android:style/Theme.Dialog">
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...