【问题标题】:Dialog buttons with long text not wrapping / squeezed out - material theme on android 5.0 lollipop带有长文本的对话框按钮不换行/挤出 - android 5.0 lollipop 上的材质主题
【发布时间】:2015-01-27 00:51:48
【问题描述】:

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

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

截图:

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

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

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

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

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

非常感谢您的帮助。提前致谢。

编辑: 要跟进,请参阅我自己在 12 月 3 日的回答,这不是解决方案。

【问题讨论】:

  • 你试过直接在按钮对象上调用 setSingleLine(false) 吗?
  • 谢谢,但是如何获取 AlertDialog 的按钮对象?
  • @Nikola - 好的,我尝试了你的建议,但没有改变。此外,当我将固定宽度/重量设置为“buttonBarButtonStyle”时,它实际上会产生多行,但这显然不是解决方案..
  • 你能发布你是如何尝试在你的主题中设置 buttonBarStyle 的吗?
  • @Mus 看我自己的答案..

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


【解决方案1】:

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

代码 导入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>

结果

【讨论】:

  • 这很好用,但是空的捕获让我有点畏缩
  • @dan-chaltiel 例如,如果某些制造商将警报对话框的默认布局更改为 RelativeLayout,则防止崩溃所需的空捕获
【解决方案2】:

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

以下是我尝试使用 buttonBarStyle 和 buttonBarButtonStyle 设置按钮样式以实现任何改进的方法 - 请在此处查看结果:

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

<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>

【讨论】:

  • 由于文本在 Material 上被强制全部大写,因此占用了更多空间并导致添加换行符。我知道这并不优雅,但请尝试缩短按钮标签或减小对话框按钮的文本大小。另外,给了你一些代表,所以当你刚开始的时候可能会很烦人:)
  • @Mus - 非常感谢您的代表。很明显,Material 上的 Buttons 由于大写、粗体以及宽大的填充和背景而占用了更多空间。但它们仍然应该像 Holo 中一样自然地表现(必要时扩大,绝对必要时断线),而不仅仅是消失。
  • 对我来说这实际上看起来像一个 Android / Material 主题错误。如果我不想改变 Material 的外观和感觉,我可能不得不彻底缩短几个按钮文本,就像 Mus 也提到的那样。太糟糕了,例如我喜欢“不再显示”之类的按钮文本,而不是“隐藏”之类的按钮文本,这不是很清楚。
  • 没问题,您可以使用“不再显示”复选框
  • 如果您必须针对低于21 的操作系统版本,要继承哪些父样式,我收到一条错误消息,指出该样式仅在API 21 中可用,当使用以下内容时: "@android:style/Widget.Material.Light.Button.Borderless.Colored” 作为父样式。
【解决方案3】:

为感兴趣的人总结一下这个主题:

Android Material 主题似乎在警报对话框中存在自动按钮宽度跨度的错误。

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

似乎并没有仅仅通过对 buttonBarStyle 和/或 buttonBarButtonStyle 进行更改来解决问题,因为它们的样式默认情况下不会限制按钮文本被包裹在多行中。

当然,Material 主题对话框按钮通常比其他主题需要更多空间,这是由于大写、粗体和宽大的填充和背景,但这不是问题的根源,它只是让它比样式更早出现需要更少的空间。

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

【讨论】:

  • 这并不总是有效的,有些语言本身就有很长的翻译,即使是简单的英语作品,如 OK、Continue 等。
【解决方案4】:

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

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) {

            }
        }
    });

【讨论】:

  • 效果很好,但只有底部按钮右对齐。
【解决方案5】:

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

【讨论】:

  • 这在有足够空间的平板电脑上看起来很糟糕
【解决方案6】:

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

这可以解决问题,并且只会在需要时包装按钮。我一直在使用它,因为即使是两个按钮的对话框也可能需要用德语包装,而三按钮的对话框肯定需要它在许多语言中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-18
    • 2015-05-23
    • 2015-05-14
    • 2020-09-12
    • 2020-01-28
    • 1970-01-01
    • 2022-10-24
    • 2022-01-11
    相关资源
    最近更新 更多