46

У меня есть DialogFragment, чтобы показать View как всплывающее окно. Окно появляется всегда посередине экрана. Есть ли способ установить положение окна DialogFragment? Я просмотрел source code, но ничего не смог найти.Позиция DialogFragment в Android

ответ

77

попробовать что-то вроде этого:

@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); 
    ... 

или другие методы getDialog().getWindow().

Обязательно установите позицию после вызова заданного содержимого.

+0

спасибо Сальтайт я поддержал ваш ответ. Однако, у меня есть вопрос.Почему вы меняете WindowManager.LayoutParam p? setGravity(), похоже, делает трюк для установки окна наверху. По-видимому, никаких негативных последствий для LayoutParams не наблюдается, когда я тестировал его или когда читал документацию о setGravity. – flobacca

+0

Вопрос был «как установить позицию», я не предполагал, что он имел в виду «верх», поэтому я привел пример установки нескольких атрибутов для получения желаемого эффекта. – Steelight

+0

+1 потому что это показало мне правильное направление. Что в конечном итоге сработало для меня: http://stackoverflow.com/a/20419231/56285 – Jonik

3

Я использую класс PopupWindow для этой цели, потому что вы можете указать местоположение и размер представления.

+13

PopupWindow - это не фрагмент, так что это довольно большая головная боль. –

4

getDialog().getWindow() не будет работать для DialogFragment, так как getWindow() вернет null, если хостинг-активность не отображается, а это не значит, что вы пишете приложение на основе фрагментов. Вы получите NullPointerException при попытке getAttributes().

Я рекомендую ответ Mobistry. Если у вас уже есть класс DialogFragment, переключиться не стоит. Просто замените метод onCreateDialog тем, который создает и возвращает PopupWindow. Затем вы сможете повторно использовать View, который вы подаете, в AlertDialog.builder.setView() и позвонить по номеру (PopupWindow object).showAtLocation().

67

Правильно, я ударил головой о стену в течение часа или двух с этим, прежде чем, наконец, получив DialogFragment, как я хотел.

Я строию на Steelight's answer здесь. Это самый простой и надежный подход, который я нашел.

@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)); 
} 

Обратите внимание, что params.width и params.softInputMode (используется в ответ Steelight в) не имеют значения для этого.


Ниже приведен более полный пример. То, что мне действительно нужно, - выровнять флажок «подтвердить» диалогового окна «Диалоговое окно» рядом с «исходным» или «родительским» представлением, в моем случае - ImageButton.

Я решил использовать DialogFragment вместо любого пользовательского фрагмента, потому что он дает вам «диалоговые» функции бесплатно (закрытие диалогового окна, когда пользователь щелкает за его пределами и т. Д.).

Example ConfirmBox
Пример ConfirmBox выше его «источник» ImageButton (мусорка)

/** 
* 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); 
    } 
} 

Это довольно легко сделать выше более общего пользования, добавляя параметры конструктора или сеттеры по мере необходимости. (Мой окончательный ConfirmBox имеет стилизованную кнопку (внутри некоторые границ и т.д.), чьи текст и View.OnClickListener может быть настроена в коде.)

+0

Удивительный лучший ответ, который я нашел. –

+0

Ребята, качайте - спасибо - мне любопытно, почему я не могу просто установить это в XML-фрагменте? ** Что я не понимаю как хромого iOS-разработчика? спасибо людям! :) – Fattie

+0

Grt ответ !! У меня возникла какая-либо проблема: в моей сценарии кнопка «источник» (ниже которой должен отображаться фрагмент диалога) изменения позиции при изменении ориентации экрана, поэтому при изменении ориентации фрагмент диалога не обновляет позицию в соответствии с положением ' source'. Не могли бы вы дать мне некоторый намек на то, как это сделать. – Dory

3

Вы должны переопределить onResume() метод в вашем DialogFragment как следующее:

@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(); 
} 
Смежные вопросы