Posizione di DialogFragment in Android
-
13-12-2019 - |
Domanda
Ho un DialogFragment
per mostrare a View
come una schermata popup.La finestra appare sempre al centro dello schermo.C'è un modo per impostare la posizione di DialogFragment
finestra?Ho esaminato il codice sorgente ma non sono ancora riuscito a trovare nulla.
Soluzione
Prova qualcosa del genere:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
getDialog().getWindow().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
p.width = ViewGroup.LayoutParams.MATCH_PARENT;
p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
p.x = 200;
...
getDialog().getWindow().setAttributes(p);
...
.
o altri metodi per getDialog().getWindow()
.
Assicurarsi di impostare la posizione dopo aver chiamato il contenuto di set.
Altri suggerimenti
Giusto, ho sbattuto la testa contro il muro per un'ora o due con questo, prima di riuscirci finalmente DialogFragment
posizionato come volevo.
Sto continuando La risposta di Steelight Qui.Questo è l'approccio più semplice e affidabile che ho trovato.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) {
Window window = getDialog().getWindow();
// set "origin" to top left corner, so to speak
window.setGravity(Gravity.TOP|Gravity.LEFT);
// after that, setting values for x and y works "naturally"
WindowManager.LayoutParams params = window.getAttributes();
params.x = 300;
params.y = 100;
window.setAttributes(params);
Log.d(TAG, String.format("Positioning DialogFragment to: x %d; y %d", params.x, params.y));
}
Notare che params.width
E params.softInputMode
(usati nella risposta di Steelight) sono irrilevanti per questo.
Di seguito è riportato un esempio più completo.Ciò di cui avevo veramente bisogno era allineare un DialogFragment "casella di conferma" accanto a una vista "sorgente" o "genitore", nel mio caso un ImageButton.
Ho scelto di utilizzare DialogFragment, anziché qualsiasi frammento personalizzato, perché offre funzionalità di "dialogo" gratuite (chiudi la finestra di dialogo quando l'utente fa clic al di fuori di essa, ecc.).
Esempio confirmbox sopra il suo ImageButton "fonte" (cestino)
/**
* A custom DialogFragment that is positioned above given "source" component.
*
* @author Jonik, https://stackoverflow.com/a/20419231/56285
*/
public class ConfirmBox extends DialogFragment {
private View source;
public ConfirmBox() {
}
public ConfirmBox(View source) {
this.source = source;
}
public static ConfirmBox newInstance(View source) {
return new ConfirmBox(source);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, R.style.Dialog);
}
@Override
public void onStart() {
super.onStart();
// Less dimmed background; see https://stackoverflow.com/q/13822842/56285
Window window = getDialog().getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.dimAmount = 0.2f; // dim only a little bit
window.setAttributes(params);
// Transparent background; see https://stackoverflow.com/q/15007272/56285
// (Needed to make dialog's alpha shadow look good)
window.setBackgroundDrawableResource(android.R.color.transparent);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Put your dialog layout in R.layout.view_confirm_box
View view = inflater.inflate(R.layout.view_confirm_box, container, false);
// Initialise what you need; set e.g. button texts and listeners, etc.
// ...
setDialogPosition();
return view;
}
/**
* Try to position this dialog next to "source" view
*/
private void setDialogPosition() {
if (source == null) {
return; // Leave the dialog in default position
}
// Find out location of source component on screen
// see https://stackoverflow.com/a/6798093/56285
int[] location = new int[2];
source.getLocationOnScreen(location);
int sourceX = location[0];
int sourceY = location[1];
Window window = getDialog().getWindow();
// set "origin" to top left corner
window.setGravity(Gravity.TOP|Gravity.LEFT);
WindowManager.LayoutParams params = window.getAttributes();
// Just an example; edit to suit your needs.
params.x = sourceX - dpToPx(110); // about half of confirm button size left of source view
params.y = sourceY - dpToPx(80); // above source view
window.setAttributes(params);
}
public int dpToPx(float valueInDp) {
DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
}
È abbastanza semplice rendere quanto sopra più generale aggiungendo parametri o setter del costruttore secondo necessità.(La mia finale ConfirmBox
ha un pulsante con stile (all'interno di alcuni bordi, ecc.) il cui testo e View.OnClickListener
può essere personalizzato nel codice.)
getDialog().getWindow()
non funzionerà per un DialogFragment
come getWindow()
restituirà NULL se l'attività di hosting non è visibile, che non è se stai scrivendo un'app basata su frammenti.Otterrai un NullPointerException
quando si tenta getAttributes()
.
Raccomando la risposta della Moutry.Se hai già una classe di dialogoFagment, non è troppo difficile passare.Basta sostituire il metodo OnCreateDialog con uno che costruisce e restituisce un popupwindow.Quindi dovresti essere in grado di riutilizzare la vista che si fornisce al AlertDialog.builder.setView()
e chiamare (PopupWindow object).showAtLocation()
.
È necessario sovrascrivere il metodo OnResume () nella finestra di dialogo come segue:
@Override
public void onResume() {
final Window dialogWindow = getDialog().getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.x = 100; // set your X position here
lp.y = 200; // set your Y position here
dialogWindow.setAttributes(lp);
super.onResume();
}
. Sto usando la classe POPUPWINDOW per questo scopo perché è possibile specificare la posizione e la dimensione della vista.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(mActivity, R.style.BottomDialog);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); //
dialog.setContentView(R.layout.layout_video_live);
dialog.setCanceledOnTouchOutside(true);
Window window = dialog.getWindow();
assert window != null;
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM; //psotion
lp.width = WindowManager.LayoutParams.MATCH_PARENT; // fuill screen
lp.height = 280;
window.setAttributes(lp);
return dialog;
}
. Sto usando AppCompatDialogFragment
da android.support.v7.app.AppCompatDialogFragment
e voglio allineare il frammento di dialogo sulla parte inferiore dello schermo e rimuovere anche tutti i bordi, specialmente dovevo impostare la larghezza del contenuto per abbinare il genitore.
Allora, volevo da questo (sfondo giallo proviene dal rootlayout del frammento di dialogo):
Ottieni questo:
Nessuna delle soluzioni abate ha funzionato.Quindi, sono riuscito a farlo:
fun AppCompatDialogFragment.alignToBottom() {
dialog.window.apply {
setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
decorView.apply {
// Get screen width
val displayMetrics = DisplayMetrics().apply {
windowManager.defaultDisplay.getMetrics(this)
}
setBackgroundColor(Color.WHITE) // I don't know why it is required, without it background of rootView is ignored (is transparent even if set in xml/runtime)
minimumWidth = displayMetrics.widthPixels
setPadding(0, 0, 0, 0)
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
invalidate()
}
}
}
.