Posição do DialogFragment no Android
-
13-12-2019 - |
Pergunta
eu tenho um DialogFragment
para mostrar um View
como uma tela pop-up.A Janela aparece sempre no meio da tela.Existe uma maneira de definir a posição do DialogFragment
janela?Eu olhei para o Código fonte mas ainda não consegui encontrar nada.
Solução
Tente algo assim:
@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);
...
ou outros métodos para getDialog().getWindow()
.
certifique-se de definir a posição após chamar set-content.
Outras dicas
Certo, bati a cabeça na parede por uma ou duas horas com isso, antes de finalmente conseguir DialogFragment
posicionado como eu queria.
Estou construindo A resposta da Steelight aqui.Esta é a abordagem mais simples e confiável que encontrei.
@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));
}
Observe que params.width
e params.softInputMode
(usados na resposta do Steelight) são irrelevantes para isso.
Abaixo está um exemplo mais completo.O que eu realmente precisava era alinhar um DialogFragment de "caixa de confirmação" ao lado de uma visualização "fonte" ou "pai", no meu caso, um ImageButton.
Optei por usar o DialogFragment, em vez de qualquer Fragment personalizado, porque ele oferece recursos de "caixa de diálogo" gratuitamente (fechar a caixa de diálogo quando o usuário clicar fora dela, etc.).
Exemplo de ConfirmBox acima de seu ImageButton "fonte" (lixeira)
/**
* 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);
}
}
É muito fácil tornar o uso acima mais geral adicionando parâmetros de construtor ou setters conforme necessário.(Meu último ConfirmBox
tem um botão estilizado (dentro de algumas bordas, etc.) cujo texto e View.OnClickListener
pode ser personalizado no código.)
getDialog().getWindow()
não funcionará por um DialogFragment
como getWindow()
retornará nulo se a atividade de hospedagem não estiver visível, o que não acontece se você estiver escrevendo um aplicativo baseado em fragmentos.Você receberá um NullPointerException
quando você tenta getAttributes()
.
Eu recomendo a resposta do Mobistry.Se você já possui uma classe DialogFragment, não é muito difícil mudar.Basta substituir o método onCreateDialog por um que construa e retorne um PopupWindow.Então você poderá reutilizar a visualização fornecida para AlertDialog.builder.setView()
, e ligue (PopupWindow object).showAtLocation()
.
Você precisa substituir o método onResume() em seu DialogFragment como 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();
}
Estou usando a classe PopupWindow para essa finalidade porque você pode especificar a localização e o tamanho da visualização.
@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;
}
estou usando AppCompatDialogFragment
de android.support.v7.app.AppCompatDialogFragment
e quero alinhar o fragmento da caixa de diálogo à parte inferior da tela e também remover todas as bordas, especialmente porque precisava definir a largura do conteúdo para corresponder ao pai.
Então, eu queria isso (o fundo amarelo vem do rootLayout do fragmento de diálogo):
Pegue isto:
Nenhuma das soluções acima funcionou.Então, consegui fazer isso:
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()
}
}
}