【问题标题】:Position of DialogFragment in AndroidDialogFragment在Android中的位置
【发布时间】:2012-03-30 16:51:39
【问题描述】:

我有一个DialogFragment 来显示一个View 就像一个弹出屏幕。 窗口始终出现在屏幕中间。 有没有办法设置DialogFragment 窗口的位置? 我查看了source code,但还没有找到任何东西。

【问题讨论】:

    标签: android android-layout android-fragments android-dialogfragment


    【解决方案1】:

    我使用来自android.support.v7.app.AppCompatDialogFragmentAppCompatDialogFragment,我想将对话框片段对齐到屏幕底部并移除所有边框,特别是我需要设置内容宽度以匹配父级。

    所以,我想从这个(黄色背景来自对话框片段的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()
            }
        }
    }
    

    【讨论】:

    • 在我的例子中,需要创建全宽对话框dialog?.window?.setLayout(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
    【解决方案2】:

    如果有人想将对话框带到屏幕底部,并使其全宽,这是我的解决方案:

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

    【讨论】:

      【解决方案3】:
      @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;
      }
      

      【讨论】:

      • 请指定您通过执行此代码实现的目标。这似乎不是对所提出问题的完整答案。
      • @JuanJoséMeleroGómez 对话框将位于窗口底部。
      【解决方案4】:

      您需要在 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(); // 将“原点”设置为左上角,可以说是 window.setGravity(Gravity.TOP|Gravity.LEFT);如果不设置原点,则 x 和 y 位置将相对于屏幕中心。
      【解决方案5】:

      试试这样的:

      @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后一定要设置位置。

      【讨论】:

      • 感谢 Steelight 我赞成您的回答。不过我确实有一个问题。为什么要更改 WindowManager.LayoutParam p? setGravity() 似乎可以将窗口设置在顶部。当我测试它或阅读有关 setGravity 的文档时,似乎对 LayoutParams 没有任何不利影响。
      • 问题是“如何设置位置”,我没有假设他的意思是“顶部”,所以我给出了设置多个属性以获得任何想要的效果的示例。
      • +1 因为这向我展示了正确的方向。最终对我有用的是:stackoverflow.com/a/20419231/56285
      • 注意:该对话框将漂浮在 Android 22 及更低版本的系统导航按钮后面,由 @Kyle R 某人提供,但缺乏足够的声誉来发表评论。
      • 谢谢。 P.y 为我改变了对话框的垂直定位。我在 onStart() 中使用了这段代码,我认为这是一个完美的地方。
      【解决方案6】:

      getDialog().getWindow() 不适用于DialogFragment,因为如果托管活动不可见,getWindow() 将返回 null,如果您正在编写基于片段的应用程序则不会。当您尝试getAttributes() 时,您将获得NullPointerException

      我推荐 Mobistry 的回答。如果你已经有一个 DialogFragment 类,切换起来也不是太难。只需将 onCreateDialog 方法替换为构造并返回 PopupWindow 的方法即可。然后您应该能够重用您提供给AlertDialog.builder.setView() 的视图,并调用(PopupWindow object).showAtLocation()

      【讨论】:

        【解决方案7】:

        是的,我用这个头撞墙一两个小时,然后终于将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 的回答中使用)与此无关。


        下面是一个更完整的例子。我真正需要的是在“源”或“父”视图旁边对齐一个“确认框”DialogFragment,在我的例子中是一个 ImageButton。

        我选择使用 DialogFragment,而不是任何自定义 Fragment,因为它免费为您提供“对话框”功能(当用户在对话框之外点击时关闭对话框等)。


        在其“源”ImageButton(垃圾箱)上方的示例 ConfirmBox

        /**
         * 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 可以在代码中自定义。)

        【讨论】:

        • 我找到了很棒的最佳答案。
        • 你们摇滚的家伙 -- 谢谢 -- 我很好奇,为什么我不能在片段的 XML 中设置它? 它是什么我没有理解为一个蹩脚的iOS开发者?谢谢男人! :)
        • Grt 答案!!我有任何问题,在我的场景中source 按钮(将在其下方显示对话框片段)屏幕方向更改时的位置更改,因此在更改方向时对话框片段不会根据@ 的位置更新位置987654331@。能否请您给我一些有关如何执行此操作的提示。
        • @alfacan 这应该是公认的答案...使用替代方案可能并不总是可以接受的。
        • @Jonik 伙计们,你太棒了。你的回答,你的个人资料,你的声誉,......所有这些都很棒。
        【解决方案8】:

        我为此使用 PopupWindow 类,因为您可以指定视图的位置和大小。

        【讨论】:

        • PopupWindow 不是片段,所以这很头疼。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-30
        相关资源
        最近更新 更多