回答

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()

確保在調用set-content之後設置位置。

+0

感謝我不滿意你的答案。我確實有一個問題。你爲什麼要改變WindowManager.LayoutParam p? setGravity()似乎可以把窗口設置在頂部。當我測試它時或者當我閱讀關於setGravity的文檔時,似乎沒有任何對LayoutParams的不利影響。 – flobacca 2013-07-15 05:32:23

+0

問題是「如何設置位置」,我沒有假設他的意思是'頂部',所以我給出了設置多個屬性以獲得任何所需效果的示例。 – Steelight 2013-07-15 07:06:09

+0

+1,因爲這給我指出了正確的方向。什麼最終爲我工作:http://stackoverflow.com/a/20419231/56285 – Jonik 2013-12-06 09:13:48

3

我使用PopupWindow類來實現此目的,因爲您可以指定視圖的位置和大小。

+13

PopupWindow不是片段,所以這非常令人頭疼。 – 2013-04-17 22:41:26

4

getDialog().getWindow()將不適用於DialogFragment因爲getWindow()將返回null如果託管活動不可見,這不是如果您正在編寫基於片段的應用程序。當您嘗試getAttributes()時,您將收到NullPointerException

我推薦Mobistry的答案。如果你已經有了一個DialogFragment類,切換並不難。只需將onCreateDialog方法替換爲構造並返回PopupWindow的方法即可。然後,您應該可以重新使用您提供給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.widthparams.softInputMode(在Steelight的答案使用)是無關緊要這一點。


下面是一個更完整的例子。我真正需要的是在「source」或「parent」視圖旁邊對齊「確認框」DialogFragment,在我的情況下是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

我發現了最棒的最佳答案。 – 2014-02-26 14:36:42

+0

你們搖滾的人 - 謝謝 - 我很好奇,**爲什麼我不能在片段的XML中設置它?**作爲一個蹩腳的iOS開發者,我不理解它是什麼?感謝男人! :) – Fattie 2014-05-24 16:47:31

+0

Grt答案!我有任何問題,在我的場景'源'按鈕(下面將顯示對話框片段)位置變化的屏幕方向變化,所以改變方向時,對話框片段沒有更新位置按照' source'。請給我一些關於如何做到這一點的提示。 – Dory 2014-09-16 12:30:04

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