具有自定义视图的AlertDialog:调整大小以包装视图的内容

B T*_*B T 56 java android android-layout android-alertdialog android-dialogfragment

我在我正在构建的应用程序中遇到此问题.请忽略所有设计缺点和缺乏最佳实践方法,这纯粹是为了展示我无法解决的一个例子.

我有DialogFragment一个AlertDialog使用自定义View设置返回基本AlertDialog.Builder.setView().如果这View有特定的大小要求,我如何Dialog正确调整自身大小以显示自定义中的所有内容View

这是我一直使用的示例代码:

package com.test.test;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Use a button for launching
        Button b = new Button(this);
        b.setText("Launch");
        b.setOnClickListener(new OnClickListener() {    
            @Override
            public void onClick(View v) {
                // Launch the dialog
                myDialog d = new myDialog();
                d.show(getFragmentManager(), null);
            }
        });

        setContentView(b);
    }

    public static class myDialog extends DialogFragment {

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {           
            // Create the dialog
            AlertDialog.Builder db = new AlertDialog.Builder(getActivity());
            db.setTitle("Test Alert Dialog:");
            db.setView(new myView(getActivity()));

            return db.create();
        }

        protected class myView extends View {
            Paint p = null;

            public myView(Context ct) {
                super(ct);

                // Setup paint for the drawing
                p = new Paint();
                p.setColor(Color.MAGENTA);
                p.setStyle(Style.STROKE);
                p.setStrokeWidth(10);
            }

            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                setMeasuredDimension(800, 300);
            }

            @Override
            protected void onDraw(Canvas canvas) {
                // Draw a rectangle showing the bounds of the view
                canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), p);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Button创建A ,打开DialogFragment单击.custom View(myView)的宽度必须为800,高度为300,并且在覆盖范围内正确设置onMeasure().这View,绘制其测量界限洋红色进行调试.

800宽度比Dialog我的设备上的默认大小宽,但被剪裁而不是正确拉伸.

我查看了以下解决方案:

我推导出以下两种编码方法:

  1. 获取WindowManager.LayoutParamsDialog,并用它们覆盖myDialog.getDialog().getWindow().get/setAttributes()
  2. 使用setLayout(w, h)方法通过myDialog.getDialog().getWindow().setLayout()

我曾尝试他们无处不在,我能想到的(压倒一切onStart(),在onShowListener之后的Dialog创建和显示等),一般都可以得到,如果这两种方法能够正常工作LayoutParams是提供一个特定的值.但无论何时WRAP_CONTENT提供,都没有任何反应.

有什么建议?

编辑:

情况截图: 在此输入图像描述

特定值的屏幕截图(在这里输入注释900,850没有覆盖视图的整个宽度,这在整个窗口正在调整的情况下是有意义的.因此,如果需要另一个,则提供 - 为什么WRAP_CONTENT必要/固定的原因值不合适): 在此输入图像描述

B T*_*B T 61

我有一个工作的解决方案,说实话,我认为挖掘方式太深,无法获得如此简单的结果.但这里是:

究竟发生了什么:

通过Dialog使用Hierarchy Viewer打开布局,我能够检查整个布局AlertDialog以及究竟发生了什么: 在此输入图像描述

蓝色亮点是所有的高电平部分的(Window,帧的Dialog视觉风格等),并从所述的端部蓝色向下是,其中用于所述部件AlertDialog顷(红色 =标题,黄色 =一个滚动视图存根,也许对列表AlertDialog小号,绿色 = Dialog内容即自定义视图,橙色 =按钮).

从这里可以清楚地看到,7视图路径(从蓝色开始到绿色结束)是未正确的WRAP_CONTENT.看着LayoutParams.width每一个都View透露了所有的东西都被给定了LayoutParams.width = MATCH_PARENT(我猜在顶部)一个大小被设定.因此,如果您遵循该树,很明显您View在树底部的自定义将永远无法影响该树的大小Dialog.

那么现有的解决方案在做什么呢?

  • 在我的问题中提到的两种编码方法都只是获得顶部View并修改它LayoutParams.显然,View树中的所有对象都与父级匹配,如果顶级设置为静态大小,则整体Dialog将改变大小.但是如果顶级设置为WRAP_CONTENT,View则树中的所有其他对象仍然在查找树以"匹配他们的父母",而不是向下看树以"包裹它们的内容".

如何解决问题:

坦率地说,改变影响路径中LayoutParams.width的所有View对象WRAP_CONTENT.

我发现这只能在调用onStart生命周期步骤之后完成DialogFragment.所以onStart实现如下:

@Override
public void onStart() { 
    // This MUST be called first! Otherwise the view tweaking will not be present in the displayed Dialog (most likely overriden)
    super.onStart();

    forceWrapContent(myCustomView);
}
Run Code Online (Sandbox Code Playgroud)

然后是适当修改View层次结构的函数LayoutParams:

protected void forceWrapContent(View v) {
    // Start with the provided view
    View current = v;

    // Travel up the tree until fail, modifying the LayoutParams
    do {
        // Get the parent
        ViewParent parent = current.getParent();    

        // Check if the parent exists
        if (parent != null) {
            // Get the view
            try {
                current = (View) parent;
            } catch (ClassCastException e) {
                // This will happen when at the top view, it cannot be cast to a View
                break;
            }

            // Modify the layout
            current.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
        }
    } while (current.getParent() != null);

    // Request a layout to be re-done
    current.requestLayout();
}
Run Code Online (Sandbox Code Playgroud)

以下是工作结果: 在此输入图像描述

它让我感到困惑的是为什么整个Dialog人不希望WRAP_CONTENT用一个明确的minWidth集合来处理所有符合默认大小的情况,但我确信它有一个很好的理由(它会有兴趣听到它) .

  • myCustomView假设是什么?我传入了getCurrentFocus()编辑:在对话框使用的视图中传递,得到它!这很棒!Edit2:我似乎在右边有一些填充 (3认同)

swe*_*sen 33

dialog.show();
Run Code Online (Sandbox Code Playgroud)

只是用

dialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, yourHeight);
Run Code Online (Sandbox Code Playgroud)

非常简单的解决方案,但它适用于我.我正在扩展一个对话框但是假设这也适用于DialogFragment.

  • 我有一个扩展Dialog的类,这个代码在super.show();之后的show()中重写.我也把它们都换成了WRAP_CONTENT; 那很好. (2认同)

Sim*_*mon 12

AlertDialog使用这两个窗口属性来定义它们的最小尺寸,以便在平板电脑上它们以合理的宽度浮动在屏幕的中心.

http://developer.android.com/reference/android/R.attr.html#windowMinWidthMajor http://developer.android.com/reference/android/R.attr.html#windowMinWidthMinor

您可以扩展所选​​的默认对话框样式,并更改值以应用您自己的逻辑.


Ron*_*ler 5

这对我来说没问题:

WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialog.show();
dialog.getWindow().setAttributes(lp);
Run Code Online (Sandbox Code Playgroud)