与自定义视图AlertDialog:调整换行视图的内容 [英] AlertDialog with custom view: Resize to wrap the view's content
问题描述
我一直有一个应用程序我建立这个问题。请忽略所有的设计缺陷和缺乏最佳实践方法,这纯粹是为了展示我解决不了什么的例子。
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:
- 获得
WindowManager.LayoutParams
的对话框的
并利用覆盖它们myDialog.getDialog ().getWindow()。获取/ setAttributes()
- 到
myDialog.getDialog使用
的setLayout(W,H)
()方法。getWindow()的setLayout()
- Get the
WindowManager.LayoutParams
of theDialog
and override them usingmyDialog.getDialog().getWindow().get/setAttributes()
- Using the
setLayout(w, h)
method throughmyDialog.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 AlertDialog
s, 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 itsLayoutParams
. Obviously, with allView
objects in the tree matching the parent, if the top level is set a static size, the wholeDialog
will change size. But if the top level is set toWRAP_CONTENT
, all the rest of theView
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屋!