与自定义视图AlertDialog:调整换行视图的内容 [英] AlertDialog with custom view: Resize to wrap the view's content

查看:530
本文介绍了与自定义视图AlertDialog:调整换行视图的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直有一个应用程序我建立这个问题。请忽略所有的设计缺陷和缺乏最佳实践方法,这纯粹是为了展示我解决不了什么的例子。

I have been having this problem in an application I am building. Please ignore all of the design shortcomings and lack of best practice approaches, this is purely to show an example of what I cannot solve.

我有 DialogFragment 返回一个基本的 AlertDialog 用自定义的查看设置使用 AlertDialog.Builder.setView()。如果这个查看有特定的尺寸要求,我怎么了对话框来正确地调整自身以显示所有的在自定义内容查看

I have DialogFragment which returns a basic AlertDialog with a custom View set using AlertDialog.Builder.setView(). If this View has a specific size requirement, how do I get the Dialog to correctly resize itself to display all of the content in the custom View?

这是例子code我一直在使用:

This is the example code I have been using:

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

A 按钮创建,这将打开 DialogFragment 上点击。自定义查看 MyView的)需要有一个宽度为800和300的高度是正确的设置 onMeasure的倍率()。这查看,绘制其测量界限洋红色进行调试。

A Button is created, which opens the DialogFragment on a click. The custom View (myView) is required to have a width of 800 and height of 300 which is correctly set in an override of onMeasure(). This View, draws its measured bounds in magenta for debugging purposes.

800宽度比默认的对话框尺寸设备上宽,但被裁剪,而不是正确地伸展。

The 800 width is wider than the default Dialog size on my device, but is clipped rather than stretching correctly.

我已经通过了以下解决方案看:

I have looked through the following solutions:

  • <一个href="http://stackoverflow.com/questions/8456143/dialogfragment-getdialog-returns-null">DialogFragment.getDialog返回null
  • <一个href="http://stackoverflow.com/questions/4406804/how-to-control-the-width-and-height-of-default-alert-dialog-in-android">how来控制机器人的宽度和默认警报对话框的高度?
  • 警报对话框或自定义警告对话框 <到
  • 尺寸/ LI>
  • DialogFragment.getDialog returns null
  • how to control the width and height of default alert dialog in Android?
  • Size of Alert Dialog or Custom Alert Dialog

我已经推断出以下两种编码方式:

I have deduced the following two coding approaches:

  1. 获得 WindowManager.LayoutParams 对话框的并利用覆盖它们 myDialog.getDialog ().getWindow()。获取/ setAttributes()
  2. myDialog.getDialog使用的setLayout(W,H)()方法。getWindow()的setLayout()
  1. Get the WindowManager.LayoutParams of the Dialog and override them using myDialog.getDialog().getWindow().get/setAttributes()
  2. Using the setLayout(w, h) method through myDialog.getDialog().getWindow().setLayout()

我已经试过他们无处不在我能想到的(覆盖 ONSTART(),在 onShowListener ,后对话框创建和显示等),一般可以得到两种方法,如果的LayoutParams 被提供的正常工作< STRONG>特定值。但每当 WRAP_CONTENT 提供,没有任何反应。

I have tried them everywhere I can think of (overriding onStart(), in a onShowListener, after the Dialog is created and shown, etc) and can generally get both methods to work correctly if the LayoutParams are supplied a specific value. But whenever WRAP_CONTENT is supplied, nothing happens.

有什么建议?

编辑:

情况截图:

Screenshot of the situation:

一个特定值的屏幕截图(注意900此处输入,850不覆盖视图,这使得给定的整个窗口感正在调整的整个宽度使提供 - 如果另一个需要 - 之所以 WRAP_CONTENT 是必不可少/固定值不适合):

Screenshot of a specific value (note 900 is entered here, 850 doesn't cover the entire width of the View, which makes sense given the entire window is being adjusted. So that provides - if another was needed - reason why WRAP_CONTENT is essential / fixed values are not appropriate):

推荐答案

我有说实话一个有效的解决方案,我想挖的方式太深获得这样一个简单的结果。但在这里,它是:

I have a working solution that to be honest, I think digs way too deep to obtain such a simple result. But here it is:

究竟是什么发生了什么:

通过与层次打开对话框布局浏览器,我可以检查整个布局的 AlertDialog 键,究竟发生了什么事情:

By opening the Dialog layout with the Hierarchy Viewer, I was able to examine the entire layout of the AlertDialog and what exactly what was going on:

蓝色亮点是所有高级别部分(窗口对话框架视觉风格,等等),并从年底在蓝色下来就是其中的各个部件的 AlertDialog 是(红色 =标题, =滚动视图存根,也许对列表 AlertDialog S,绿色 = 对话框内容即自定义视图,橙色 =按钮)。

The blue highlight is all of the high level parts (Window, frames for the Dialog visual style, etc) and from the end of the blue down is where the components for the AlertDialog are (red = title, yellow = a scrollview stub, maybe for list AlertDialogs, green = Dialog content i.e. custom view, orange = buttons).

从这里很明显,7视图路径(从的蓝色的开始到结束的绿色)是什么正确未能 WRAP_CONTENT 。纵观 LayoutParams.width 每个查看表明,所有给出 LayoutParams.width = MATCH_PARENT 和地方(我猜在顶部)一个大小设置。所以,如果你跟着那棵树,很显然,您的自定义查看在树的底部,将永远能够影响的大小在对话框

From here it was clear that the 7-view path (from the start of the blue to the end of the green) was what was failing to correctly WRAP_CONTENT. Looking at the LayoutParams.width of each View revealed that all are given LayoutParams.width = MATCH_PARENT and somewhere (I guess at the top) a size is set. So if you follow that tree, it is clear that your custom View at the bottom of the tree, will never be able to affect the size of the Dialog.

那么,什么是现有的解决方案在干什么?

So what were the existing solutions doing?

  • 双方的的的编码方法的在我的问题提到了仅仅让顶部查看并修改其的LayoutParams 。很显然,在树中的所有查看对象匹配的父母,如果顶层设置一个静态的大小,整个对话框会改变大小。但是,如果在顶层设置为 WRAP_CONTENT ,在树中的查看对象中的其他一切都还在的查找树的以符合他们的父母,而不是的低头树的包装他们的内容。
  • Both of the coding approaches mentioned in my question were simply getting the top View and modifying its LayoutParams. Obviously, with all View objects in the tree matching the parent, if the top level is set a static size, the whole Dialog will change size. But if the top level is set to WRAP_CONTENT, all the rest of the View objects in the tree are still looking up the tree to "MATCH their PARENT", as opposed to looking down the tree to "WRAP their CONTENT".

如何来解决这个问题:

说白了,改 LayoutParams.width 所有查看的影响路径对象是 WRAP_CONTENT

Bluntly, change the LayoutParams.width of all View objects in the affecting path to be WRAP_CONTENT.

我发现,这只能 ONSTART 之后完成的 DialogFragment 被称为生命周期的一步。因此, ONSTART 是等来实现:

I found that this could only be done AFTER onStart lifecycle step of the DialogFragment is called. So the onStart is implemented like:

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

然后函数适当地修改查看层次结构的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();
}

这里是工作的结果:

And here is the working result:

这混淆了我,为什么整个对话框不想成为 WRAP_CONTENT 有明确的了minWidth 设置为处理适合里面的默认大小所有的情况下,但我敢肯定有一个很好的理由事情是这样的(有兴趣听听吧)。

It confuses me why the entire Dialog would not want to be WRAP_CONTENT with an explicit minWidth set to handle all cases that fit inside the default size, but I'm sure there is a good reason for it the way it is (would be interested to hear it).

这篇关于与自定义视图AlertDialog:调整换行视图的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆