对话框按钮与长文本不包装/挤出 - android 5.0棒棒糖上的材料主题

时间:2014-11-28 11:05:51

标签: android button alertdialog android-5.0-lollipop material-design

在优化棒棒糖上的素材主题应用时,我遇到了这个恼人的问题:

每当对话框按钮上有长文本时,总体上不符合按钮栏宽度,对于这些按钮,文本不会像以前的主题一样包裹在多行中。相反,以下按钮被挤出对话框,无法访问(见下图)。

截图: http://s29.postimg.org/3vqp884cn/dialogs_light_holo_material.png

到目前为止,我已经花了很多时间处理这个问题,而我在互联网上找到的关于它的唯一主题是: https://code.google.com/p/android/issues/detail?id=78302

所以我在那里接受建议并在这里提出这个问题..

我尝试过查看源代码(按钮用maxLines = 2定义)并在buttonBarStyle和buttonBarButtonStyle上更改不同的参数但没有成功。

我正在寻找一个简单的样式解决方案,因此不想使用第三方库。

这可能只是模拟器问题吗?我不这么认为。

非常感谢帮助。提前谢谢。

修改 要跟进,请参阅12月3日我自己的回答,这不是一个解决方案。

6 个答案:

答案 0 :(得分:18)

这可以通过使用堆叠按钮而不是行按钮来解决。在这里我的解决方法是如何使用AppCompat lib实现它:

<强>代码         import android.support.v7.app.AlertDialog;

    AlertDialog.Builder builder;
    builder = new AlertDialog.Builder(context, R.style.StackedAlertDialogStyle);
    builder.setTitle("Title");
    builder.setMessage("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dignissim purus eget gravida mollis. Integer in auctor turpis. Morbi auctor, diam eget vestibulum congue, quam arcu pulvinar dui, blandit egestas erat enim non ligula." +
            " Nunc quis laoreet libero. Aliquam consectetur nibh eu arcu eleifend efficitur.");
    builder.setPositiveButton("Positive Button", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
        }
    });
    builder.setNeutralButton("Neutral Button", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
        }
    });
    builder.setNegativeButton("Cancel Button", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
        }
    });
    AlertDialog alertDialog = builder.create();
    alertDialog.show();
        try{
            final Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
            LinearLayout linearLayout = (LinearLayout) button.getParent();
            linearLayout.setOrientation(LinearLayout.VERTICAL);
        } catch(Exception ex){
            //ignore it
        }

<强>风格

<style name="StackedAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
    <item name="buttonBarButtonStyle">@style/StackedButtonBarButtonStyle</item>
</style>

<style name="StackedButtonBarButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
    <item name="android:layout_gravity">right</item>
</style>

<强>结果

Stacked Alert Dialog

答案 1 :(得分:14)

跟进 - 由于我的初学者声誉,我无法发布超过两个链接,因此我必须回答我的问题,而不是编辑它。

下面是我尝试使用buttonBarStyle和buttonBarButtonStyle设置样式以实现任何改进的方式 - 请参阅此处的结果: http://s12.postimg.org/uyp0p0e6l/dialog_material_button_fix_tests_1.png

不幸的是,这些显然不是理想的解决方案。

<resources>
    <style name="AppBaseTheme" parent="android:Theme.Material.Light">
        <!-- AlertDialog Style override in order to try to fix non line breaking buttons -->
        <item name="android:alertDialogTheme">@style/CustomAlertDialogStyle</item>
    </style>  

    <style name="CustomAlertDialogStyle" parent="android:Theme.Material.Light.Dialog.Alert">
        <item name="android:buttonBarButtonStyle">@style/CustomButtonBarButtonStyle</item>
        <item name="android:buttonBarStyle">@style/CustomButtonBarStyle</item>
    </style>

    <style name="CustomButtonBarStyle" parent="@android:style/Widget.Material.Light.ButtonBar.AlertDialog">
        <!-- Making sure, the button bar uses parent width and is not restricted in height -->
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:height">@null</item>
        <item name="android:minHeight">@null</item>
    </style>

    <style name="CustomButtonBarButtonStyle" parent="@android:style/Widget.Material.Light.Button.Borderless.Colored">
        <!-- Setting the weight as follows should result in equally wide buttons filling the alert dialog width,
            but instead they span further out of the dialog, breaking in multiple lines though -->
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_weight">1</item>
        <!-- setting a fixed width as follows results in narrow buttons with line breaks, but of course this is not a solution -->
        <!-- <item name="android:width">100dp</item> -->
    </style>

</resources>

答案 2 :(得分:6)

为感兴趣的人总结此主题:

Android Material主题似乎在警告对话框中出现了自动按钮宽度范围的错误。

如果您有3个按钮,其中一个按钮有多个单词,则正向按钮可能会被挤出右侧的对话框,而不是多个行包含多个单词的按钮,这样所有按钮都适合按钮栏,就像基本主题/全息主题一样。

似乎没有单独通过对buttonBarStyle和/或buttonBarButtonStyle应用更改的解决方案,因为默认情况下它们的样式不限制按钮文本被多行包装。

当然,由于大写,大胆和丰富的填充和背景,材质主题对话框按钮需要比其他主题更多的空间,但这不是问题的根源,它只是使它看起来比造型更快需要的空间更少。

解决这个问题的唯一方法似乎是给你的按钮更短的标题,如果你不想设置远离Material的外观和感觉(比如使按钮文本大小更小和/或将allCaps设置为false)。

答案 3 :(得分:3)

使用以下代码,让右边的按钮和垂直排列

alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            try {
                LinearLayout linearLayout = (LinearLayout) alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).getParent();
                if (linearLayout != null) {
                    linearLayout.setOrientation(LinearLayout.VERTICAL);
                    linearLayout.setGravity(Gravity.RIGHT);
                }
            } catch (Exception ignored) {

            }
        }
    });

答案 4 :(得分:2)

非动态的快速解决方案是添加\ n以打破长字符串

答案 5 :(得分:2)

这是我提出的解决方法,借助于Andrey T(https://stackoverflow.com/a/29662638/1317564)的链接答案:

首先,创建一个实用程序方法,只有在需要打包时才会包装按钮:

public static void applyWorkaroundForButtonWidthsTooWide(Button dialogButton) {
        if (dialogButton == null)
            return;
        if (!(dialogButton.getParent() instanceof LinearLayout))
            return;            

        // Workaround for buttons too large in alternate languages.
        final LinearLayout linearLayout = (LinearLayout) dialogButton.getParent();
        linearLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                       int oldRight, int oldBottom) {
                if (right - left > 0) {
                    final int parentWidth = linearLayout.getWidth();
                    int childrenWidth = 0;
                    for (int i = 0; i < linearLayout.getChildCount(); ++i)
                        childrenWidth += linearLayout.getChildAt(i).getWidth();

                    if (childrenWidth > parentWidth) {
                        // Apply stacked buttons
                        linearLayout.setOrientation(LinearLayout.VERTICAL);
                        linearLayout.setPadding(linearLayout.getPaddingLeft(), 0, linearLayout.getPaddingRight(),
                                linearLayout.getPaddingBottom());
                        for (int i = 0; i < linearLayout.getChildCount(); ++i) {
                            if (linearLayout.getChildAt(i) instanceof Button) {
                                final Button child = (Button) linearLayout.getChildAt(i);
                                child.setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
                                final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();
                                params.width = LinearLayout.LayoutParams.MATCH_PARENT;
                                params.gravity = Gravity.END;
                                child.setLayoutParams(params);
                            } else if (linearLayout.getChildAt(i) instanceof Space) {
                                linearLayout.removeViewAt(i--);
                            }
                        }
                    }

                    linearLayout.removeOnLayoutChangeListener(this);
                }
            }
        });
    }

您可以添加其他错误处理(即尝试/捕获)并根据需要进一步自定义。

现在,在显示对话框时调用此实用程序方法:

dialog.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialogInterface) {
                    MaterialAlertDialogUtils.applyWorkaroundForButtonWidthsTooWide(dialog.getButton(AlertDialog.BUTTON_POSITIVE));
                }
            });

这样做的技巧只会在需要时包裹按钮。我到处都在使用它,因为即使是双键对话框也可能需要用德语包装,而三键式对话框肯定需要多种语言。