Position von DialogFragment in Android
-
13-12-2019 - |
Frage
Ich habe eine DialogFragment
um ein zu zeigen View
wie ein Popup-Bildschirm.Das Fenster erscheint immer in der Mitte des Bildschirms.Gibt es eine Möglichkeit, die Position des DialogFragment
fenster?Ich habe in die geschaut Quellcode konnte aber noch nichts finden.
Lösung
Versuchen Sie so etwas:
@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);
...
oder andere Methoden für getDialog().getWindow()
.
stellen Sie sicher, dass Sie die Position nach dem Aufruf von set-content festlegen.
Andere Tipps
Richtig, ich habe damit ein oder zwei Stunden lang mit dem Kopf gegen die Wand geschlagen, bevor ich endlich kam DialogFragment
positioniert wie ich wollte.
Ich baue auf Antwort von Steelight hier.Dies ist der einfachste und zuverlässigste Ansatz, den ich gefunden habe.
@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));
}
Beachten Sie, dass params.width
und params.softInputMode
(in Steelights Antwort verwendet) sind dafür irrelevant.
Unten ist ein vollständigeres Beispiel.Was ich wirklich brauchte, war, ein DialogFragment "Bestätigungsfeld" neben einer "Quell" - oder "übergeordneten" Ansicht auszurichten, in meinem Fall einen ImageButton.
Ich habe mich dafür entschieden, DialogFragment anstelle eines benutzerdefinierten Fragments zu verwenden, da es Ihnen kostenlose "Dialog" -Funktionen bietet (Dialog schließen, wenn der Benutzer außerhalb davon klickt usw.).
Beispiel Bestätigungsbox über dem ImageButton "Quelle" (Papierkorb)
/**
* 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);
}
}
Es ist ziemlich einfach, das Obige allgemeiner zu verwenden, indem Konstruktorparameter oder Setter nach Bedarf hinzugefügt werden.(Mein Finale ConfirmBox
hat eine gestaltete Schaltfläche (innerhalb einiger Ränder usw.), deren Text und View.OnClickListener
kann im Code angepasst werden.)
getDialog().getWindow()
wird nicht für eine Arbeit DialogFragment
als getWindow()
gibt null zurück, wenn die Hosting-Aktivität nicht sichtbar ist, was nicht der Fall ist, wenn Sie eine fragmentbasierte App schreiben.Sie erhalten eine NullPointerException
wenn du es versuchst getAttributes()
.
Ich empfehle die Antwort von Mobistry.Wenn Sie bereits eine DialogFragment Klasse haben, ist es nicht allzu schwer umzuschalten.Ersetzen Sie einfach die onCreateDialog-Methode durch eine, die ein PopupWindow erstellt und zurückgibt.Dann sollten Sie in der Lage sein, die von Ihnen bereitgestellte Ansicht wiederzuverwenden AlertDialog.builder.setView()
, und rufen Sie an (PopupWindow object).showAtLocation()
.
Sie müssen die onResume () -Methode in Ihrem DialogFragment wie folgt überschreiben:
@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();
}
Ich verwende zu diesem Zweck die PopupWindow-Klasse, da Sie den Speicherort und die Größe der Ansicht angeben können.
@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;
}
Ich benutze AppCompatDialogFragment
von android.support.v7.app.AppCompatDialogFragment
und ich möchte das Dialogfragment am unteren Bildschirmrand ausrichten und auch alle Ränder entfernen, insbesondere musste ich die Inhaltsbreite so einstellen, dass sie mit dem übergeordneten Element übereinstimmt.
Also, ich wollte davon (gelber Hintergrund kommt von rootLayout des Dialogfragments):
Hol dir das:
Keine der oben genannten Lösungen hat funktioniert.Also habe ich das geschafft:
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()
}
}
}