Chciałbym mieć możliwość rozmywania lub przyciemniania tła, gdy wyświetlam wyskakujące okienko za pomocą popup.showAtLocation
, i rozmywania / przyciemniania tła po popup.dismiss
wywołaniu.
Próbowałem zastosować parametry układu FLAG_BLUR_BEHIND
i FLAG_DIM_BEHIND
do mojej aktywności, ale wydaje się, że tło po prostu rozmywa się i ściemnia, gdy tylko moja aplikacja jest uruchomiona.
Jak mogę rozmywać / ściemniać tylko wyskakujące okienka?
Odpowiedzi:
Pytanie dotyczyło
Popupwindow
klasy, ale każdy udzielił odpowiedzi wykorzystujących tęDialog
klasę. Jest to prawie bezużyteczne, jeśli musisz użyćPopupwindow
klasy, ponieważPopupwindow
nie magetWindow()
metody.Znalazłem rozwiązanie, które faktycznie działa
Popupwindow
. Wymaga tylko, aby katalog główny pliku xml, którego używasz do działania w tle, to plikFrameLayout
. Możesz nadaćFramelayout
elementowiandroid:foreground
tag. Ten znacznik określa zasób, który można rysować, który zostanie nałożony na całą aktywność (to znaczy, jeśli Framelayout jest elementem głównym w pliku xml). Następnie możesz kontrolować krycie (setAlpha()
) rysowanego pierwszego planu.Możesz użyć dowolnego zasobu do rysowania, który Ci się podoba, ale jeśli chcesz uzyskać efekt ściemniania, utwórz plik xml w folderze do rysowania z
<shape>
tagiem jako głównym.<?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>
( Więcej informacji na temat elementu można znaleźć pod adresem http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape
shape
). Zauważ, że nie podałem wartości alfa w znaczniku koloru, która sprawiłaby, że element do rysowania byłby przezroczysty (np#ff000000
.). Powodem tego jest to, że jakakolwiek zakodowana na stałe wartość alfa zdaje się zastępować wszelkie nowe wartości alfa, które ustawiliśmy za pomocąsetAlpha()
w naszym kodzie, więc nie chcemy tego. Oznacza to jednak, że element do wyciągania będzie początkowo nieprzezroczysty (jednolity, nieprzezroczysty). Musimy więc uczynić go przejrzystym wonCreate()
metodzie działania.Oto kod elementu Framelayout xml:
<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>
Oto metoda onCreate () działania:
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); }
Na koniec kod do ściemniania aktywności:
layout_MainMenu.getForeground().setAlpha( 220); // dim layout_MainMenu.getForeground().setAlpha( 0); // restore
Wartości alfa przechodzą od
0
(nieprzezroczysty) do255
(niewidoczny). Powinieneś cofnąć przyciemnienie działania po zamknięciu Popupwindow.Nie załączyłem kodu do wyświetlania i zamykania Popupwindow, ale oto link do tego, jak to zrobić: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
źródło
Ponieważ
PopupWindow
po prostu dodajeView
się doWindowManager
was może wykorzystaćupdateViewLayout (View view, ViewGroup.LayoutParams params)
do zaktualizowaniaLayoutParams
swoichPopupWindow
„scontentView
po wywołaniu pokaz .. ().Ustawienie flagi okna
FLAG_DIM_BEHIND
spowoduje przyciemnienie wszystkiego za oknem. SłużydimAmount
do kontrolowania ilości przyciemnienia (od 1,0 dla całkowitego nieprzezroczystości do 0,0 dla braku przyciemnienia).Pamiętaj, że jeśli ustawisz tło na swoje
PopupWindow
, umieścicontentView
je w kontenerze, co oznacza, że musisz zaktualizować jego rodzica.Z tłem:
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);
Bez tła:
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);
Aktualizacja Marshmallow:
W M PopupWindow otacza contentView wewnątrz FrameLayout o nazwie mDecorView. Jeśli zagłębisz się w źródło PopupWindow, znajdziesz coś w rodzaju
createDecorView(View contentView)
.Głównym celem mDecorView jest obsługa wysyłania zdarzeń i przejść treści, które są nowe dla M. Oznacza to, że musimy dodać jeszcze jedną .getParent (), aby uzyskać dostęp do kontenera.Z tłem, które wymagałoby zmiany na coś takiego:
View container = (View) popup.getContentView().getParent().getParent();
Lepsza alternatywa dla API 18+
Mniej hakerskie rozwiązanie wykorzystujące
ViewGroupOverlay
:1) Zdobądź pożądany układ katalogu głównego
2) Zadzwoń
applyDim(root, 0.5f);
lubclearDim()
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(); }
źródło
WindowManager.LayoutParams
. Czy jest w pobliżu praca?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); } }); }
W pliku xml dodaj coś takiego z szerokością i wysokością jako „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>
W swojej działalności oncreate
//setting background dim when showing popup back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);
Na koniec spraw, aby było widoczne, kiedy pokazujesz swoje okno podręczne i znikało, gdy wychodzisz z tego okna.
back_dim_layout.setVisibility(View.VISIBLE); back_dim_layout.setVisibility(View.GONE);
źródło
Inną sztuczką jest użycie 2 wyskakujących okienek zamiast jednego. Pierwsze wyskakujące okienko będzie po prostu fałszywym widokiem z przezroczystym tłem, które zapewnia efekt przyciemnienia. Drugie wyskakujące okienko jest Twoim zamierzonym wyskakującym okienkiem.
Sekwencja podczas tworzenia wyskakujących okienek: Pokaż najpierw fałszywe wyskakujące okienko, a następnie żądane wyskakujące okienko.
Sekwencja podczas niszczenia: Zamknij żądane wyskakujące okienko, a następnie fałszywe okno wyskakujące.
Najlepszym sposobem na połączenie tych dwóch jest dodanie OnDismissListener i zastąpienie
onDismiss()
metody zamierzonej do przyciemnienia fikcyjnego okna wyskakującego z ich.Kod fikcyjnego okna podręcznego:
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>
Pokaż wyskakujące okienko, aby przyciemnić tło
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; }
źródło
Znalazłem na to rozwiązanie
Utwórz niestandardowe przezroczyste okno dialogowe i w nim otwórz okno podręczne:
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 dla okna dialogowego (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" />
teraz chcesz zamknąć okno dialogowe po zamknięciu okna Popup. więc
mQuickAction.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { if(dialog!=null) { dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes dialog = null; } } });
Uwaga: użyłem
NewQuickAction
wtyczki do tworzenia PopupWindow tutaj. Można to również zrobić w natywnych okienkach Popupźródło
Dla mnie działa coś w rodzaju odpowiedzi Abdelhaka Mouaamou, przetestowane na poziomie API 16 i 27.
Zamiast używać
popupWindow.getContentView().getParent()
i rzutować wynik doView
(co ulega awarii na poziomie API 16, ponieważ zwracaViewRootImpl
obiekt, który nie jest instancjąView
), po prostu używam,.getRootView()
który zwraca już widok, więc nie jest wymagane rzutowanie.Mam nadzieję, że to komuś pomoże :)
kompletny przykład roboczy zaszyfrowany razem z innych postów stackoverflow, po prostu skopiuj go i wklej, np. w odbiorniku onClick przycisku:
// 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); } }
źródło
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
to identyfikator układu, którego jasność chcesz przyciemnić.źródło
Możesz użyć
android:theme="@android:style/Theme.Dialog"
do tego. Utwórz działanie iAndroidManifest.xml
zdefiniuj je jako:<activity android:name=".activities.YourActivity" android:label="@string/your_activity_label" android:theme="@android:style/Theme.Dialog">
źródło
ok, więc podążam za odpowiedzią uhmdown dotyczącą ściemniania aktywności w tle, gdy okno pop jest otwarte. Ale stwarza to dla mnie problem. była to aktywność ściemniania i dołączanie wyskakującego okienka (oznacza to, że przyciemniona czerń jest nałożona zarówno na aktywność, jak i wyskakujące okienko, nie można ich rozdzielić).
więc próbowałem w ten sposób
utwórz plik dimming_black.xml dla efektu ściemniania,
<?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>
I dodać
background
wFrameLayout
jak tagu bazowy XML, również umieścić moje inne kontrole wLinearLayout
takilayout.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>
w końcu pokazuję wyskakujące okienko na moim
MainActivity
z dodatkowym zestawem parametrów, jak poniżej.//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);
Wynik:
to działa dla mnie, również rozwiązany problem jak skomentował BaDo . Dzięki temu
Actionbar
również można przyciemnić.Ps, nie mówię, że uhmdown jest źle. nauczyłem się z jego odpowiedzi i staram się rozwijać dla mojego problemu. Nie wiedziałem też, czy to dobry sposób, czy nie.
Wszelkie sugestie są również mile widziane i przepraszam za mój zły angielski.
źródło
Może to repozytorium pomoże ci: BasePopup
To jest moje repozytorium, które służy do rozwiązywania różnych problemów PopupWindow.
W przypadku korzystania z biblioteki, jeśli potrzebujesz rozmyć tło, wystarczy zadzwonić
setBlurBackgroundEnable(true).
Zobacz wiki po więcej szczegółów. (Język w zh-cn)
BasePopup: wiki
źródło
Ten kod działa
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);
źródło