Я хотел бы иметь возможность размывать или затемнять фон, когда я показываю свое всплывающее окно, используя popup.showAtLocation
, и не размывать / затемнять фон при popup.dismiss
вызове.
Я попытался применить параметры макета FLAG_BLUR_BEHIND
и FLAG_DIM_BEHIND
к своей деятельности, но это, похоже, просто размывает и затемняет фон, как только мое приложение запускается.
Как сделать размытие / затемнение только во всплывающих окнах?
Ответы:
Вопрос был о
Popupwindow
классе, но все дали ответы, которые используют этотDialog
класс. Это бесполезно, если вам нужно использоватьPopupwindow
класс, потому что уPopupwindow
него нетgetWindow()
метода.Я нашел решение, которое действительно работает
Popupwindow
. Требуется только, чтобы корень XML-файла, который вы используете для фоновой активности, былFrameLayout
. Вы можете присвоитьFramelayout
элементуandroid:foreground
тег. Этот тег указывает на доступный для рисования ресурс, который будет размещен поверх всего действия (то есть, если Framelayout является корневым элементом в файле xml). Затем вы можете управлять непрозрачностью (setAlpha()
) переднего плана, доступного для рисования.Вы можете использовать любой ресурс с возможностью рисования, который вам нравится, но если вам просто нужен эффект затемнения, создайте файл xml в папке с возможностью рисования с
<shape>
тегом в качестве root.<?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>
(См. Http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape для получения дополнительной информации об
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>
Вот метод Activity onCreate ():
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
(невидимый). Вы должны убрать яркость активности, когда закрываете Popupwindow.Я не включил код для отображения и закрытия всплывающего окна, но вот ссылка на то, как это можно сделать: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
источник
Так как
PopupWindow
только добавляетView
кWindowManager
вам можно использоватьupdateViewLayout (View view, ViewGroup.LayoutParams params)
для обновленияLayoutParams
вашихPopupWindow
«сcontentView
после вызова шоу .. ().Установка флажка окна
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);
Обновление Marshmallow:
В M PopupWindow оборачивает contentView внутри FrameLayout с именем mDecorView. Если вы покопаетесь в источнике PopupWindow, вы найдете что-то вроде
createDecorView(View contentView)
. Основная цель mDecorView - обрабатывать отправку событий и переходы контента, которые являются новыми для M. Это означает, что нам нужно добавить еще один .getParent () для доступа к контейнеру.С фоном, который потребует изменения чего-то вроде:
View container = (View) popup.getContentView().getParent().getParent();
Лучшая альтернатива API 18+
Менее хакерское решение, использующее
ViewGroupOverlay
:1) Получите желаемый корневой макет
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(); }
источник
WindowManager.LayoutParams
. Есть ли обходной путь?if (p != null) { //same } else { popupView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); WindowManager.LayoutParams p = (WindowManager.LayoutParams) v.getLayoutParams(); p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(v, p); } }); }
В ваш 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>
В вашей деятельности oncreate
//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);
источник
Еще одна хитрость - использовать 2 всплывающих окна вместо одного. Первое всплывающее окно будет просто фиктивным видом с полупрозрачным фоном, обеспечивающим эффект затемнения. Второе всплывающее окно - это ваше предполагаемое всплывающее окно.
Последовательность создания всплывающих окон: сначала покажите фиктивное всплывающее окно, а затем предполагаемое всплывающее окно.
Последовательность при разрушении: закройте предполагаемое всплывающее окно, а затем фиктивное всплывающее окно.
Лучший способ связать эти два - добавить 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; }
источник
Я нашел решение для этого
Создайте собственный прозрачный диалог и внутри этого диалога откройте всплывающее окно:
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. Это также можно сделать в родных всплывающих окнахисточник
Для меня работает что-то вроде ответа Абдельхака Муаму, протестированного на уровне 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. /programming/24832497 and /programming/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); } }
источник
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
это идентификатор макета, яркость которого вы хотите уменьшить.источник
Вы можете использовать
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">
источник
Хорошо , поэтому я следую ответу uhmdown для затемнения фоновой активности, когда всплывающее окно открыто. Но это создает для меня проблемы. это было затемнением активности и включало всплывающее окно (это означает, что затемненный черный слой накладывается как на активность, так и на всплывающее окно, их нельзя разделить).
поэтому я пробовал этот способ,
создайте файл 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);
Результат:
это работает для меня, также решена проблема, как прокомментировал BaDo . С помощью этого
Actionbar
также можно затемнить.Ps я не говорю, что uhmdown неправильно. Я узнал из его ответа и пытаюсь развить свою проблему. Я тоже запуталась, хороший это способ или нет.
Любые предложения также приветствуются, также извините за мой плохой английский.
источник
Может быть, вам поможет это репо: BasePopup
Это мое репо, которое используется для решения различных проблем PopupWindow.
В случае использования библиотеки, если вам нужно размыть фон, просто вызовите
setBlurBackgroundEnable(true).
См. Вики для получения более подробной информации. (Язык в zh-cn)
BasePopup: вики
источник
Этот код работает
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);
источник