我有DialogFragment一个View像弹出屏幕一样的显示。窗口始终出现在屏幕中间。有没有办法设置DialogFragment窗口的位置?我已经查看了源代码,但还没有找到任何东西。
8 回答
尝试这样的事情:
@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 后设置位置。
是的,我用这个头撞墙一两个小时,然后终于找到了DialogFragment我想要的位置。
我在这里建立了Steelight 的答案。这是我发现的最简单、最可靠的方法。
@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 的回答中使用)与此无关。
下面是一个更完整的例子。我真正需要的是在“源”或“父”视图旁边对齐一个“确认框”DialogFragment,在我的例子中是一个 ImageButton。
我选择使用 DialogFragment,而不是任何自定义 Fragment,因为它免费为您提供“对话框”功能(当用户在对话框之外单击时关闭对话框等)。

示例 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可以在代码中自定义。)
我使用AppCompatDialogFragmentfromandroid.support.v7.app.AppCompatDialogFragment并且我想将对话框片段对齐到屏幕底部并删除所有边框,特别是我需要设置内容宽度以匹配父级。
所以,我想从这个(黄色背景来自对话框片段的rootLayout):
得到这个:
上述解决方案均无效。所以,我这样做了:
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()
        }
    }
}
    您需要在 DialogFragment 中覆盖 onResume() 方法,如下所示:
@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();
}
    getDialog().getWindow()如果托管活动不可见DialogFragment,getWindow()则将返回 null ,如果您正在编写基于片段的应用程序,则不会。NullPointerException当你尝试时你会得到一个getAttributes()。
我推荐 Mobistry 的回答。如果你已经有一个 DialogFragment 类,切换起来并不难。只需将 onCreateDialog 方法替换为构造并返回 PopupWindow 的方法即可。然后您应该能够重用您提供给的 ViewAlertDialog.builder.setView()并调用(PopupWindow object).showAtLocation().
我为此目的使用 PopupWindow 类,因为您可以指定视图的位置和大小。
@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;
}
    如果有人想将对话框带到屏幕底部并使其全宽,这是我的解决方案:
    @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // the content
    final RelativeLayout root = new RelativeLayout(getActivity());
    root.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    // creating the fullscreen dialog
    final Dialog dialog = new Dialog(getActivity());
    Window dialogWindow = dialog.getWindow();
    dialog.setContentView(root);
    dialogWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
    WindowManager.LayoutParams params = dialogWindow.getAttributes();
    params.width = ViewGroup.LayoutParams.MATCH_PARENT;
    params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
    dialogWindow.setAttributes(params);
    dialogWindow.setGravity(Gravity.BOTTOM);
    return dialog;
}
    
