当肯定按钮文本变短时,如何阻止对话框标题文本缩小?

How to stop dialog title text from shrinking when positive button text gets shorter?

我想创建一个 AlertDialog,其标题文本和消息在用户执行一系列步骤时每次单击肯定按钮时都会发生变化。

一切正常,除了当用户到达第三个也是最后一个屏幕时,标题文本的大小缩小了!这似乎是因为肯定按钮文本的字符串对于最终屏幕而言较短。如果我让它变长,标题文本在最终屏幕上将不再缩小。

这是我的代码的精简版。 dialog.xml 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingStart="16dp"
    android:paddingEnd="16dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

</LinearLayout>

这是对话片段的代码:

package com.world.test.fixshrinkingdialogtitletext;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;

public class ChangeTitleDialogFragment
        extends DialogFragment {

    private static final String DIALOG_TITLE = "DIALOG_TITLE";
    private static final String TEXT_PROMPT = "TEXT_PROMPT";
    private static final String POSITIVE_BUTTON_TEXT = "POSITIVE_BUTTON_TEXT";
    private static final String SCREEN_COUNT = "SCREEN_COUNT";

    private String dialogTitle = null;
    private String textPrompt = null;
    private String positiveButtonText = null;
    private int screenCount;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            screenCount = 1;
            dialogTitle = "First Screen";
            textPrompt = "Click continue";
            positiveButtonText = "Continue";
        } else {
            dialogTitle = savedInstanceState.getString(DIALOG_TITLE);
            textPrompt = savedInstanceState.getString(TEXT_PROMPT);
            positiveButtonText = savedInstanceState.getString(POSITIVE_BUTTON_TEXT);
            screenCount = savedInstanceState.getInt(SCREEN_COUNT);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(DIALOG_TITLE, dialogTitle);
        outState.putString(TEXT_PROMPT, textPrompt);
        outState.putString(POSITIVE_BUTTON_TEXT, positiveButtonText);
        outState.putInt(SCREEN_COUNT, screenCount);
    }

    @Override
    @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        LayoutInflater inflater = getActivity().getLayoutInflater();
        @SuppressLint("InflateParams")
        final View view = inflater.inflate(R.layout.dialog, null);
        builder.setView(view);
        builder.setTitle(dialogTitle);
        builder.setMessage(textPrompt);
        builder.setPositiveButton(positiveButtonText, null);
        builder.setNegativeButton("Cancel", null);

        AlertDialog dialog = builder.create();

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {

            @Override
            public void onShow(final DialogInterface dialog) {
                final AlertDialog alertDialog = (AlertDialog) dialog;

                final Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                okButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        if (screenCount == 3) {
                            dismiss();
                        } else {
                            screenCount++;

                            dialogTitle = "Screen Number " + screenCount;
                            alertDialog.setTitle(dialogTitle);

                            if (screenCount == 3) {
                                // "OKOKOKOKO" won't cause the dialog title text to shrink!
                                positiveButtonText = "OKOKOKOK";
                                okButton.setText(positiveButtonText);
                            }
                        }
                    }
                });
            }
        });

        return dialog;
    }
}

下面是 3 个屏幕的屏幕截图(最后 2 个被裁剪):

我注意到对话框在最终屏幕上的宽度略有缩小,可能是因为布局设置为环绕其内容,并且肯定按钮上的文本较短。因此,Android 可能会自动缩小标题文本大小,以确保它仍然适合。但这是一个猜测。

有谁知道如何更新标题文本但在所有屏幕上保持相同的大小?

我发现标题文字大小的变化完全不直观。谁能解释为什么它会改变大小?这是预期的行为还是 Android 错误?

最好的解决方案不会涉及明确设置文本大小,因为如果我以后更改应用主题,我将不得不记住更改标题文本大小以匹配所有主题中的主题multi-screen 个像这样的对话。

您是否尝试过在线性布局上设置最小宽度?

例如

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"

             android:minWidth="150dp"  <!-- The size you want -->

             android:paddingStart="16dp"
             android:paddingEnd="16dp"
             android:orientation="vertical">

<TextView
    android:id="@+id/text_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceMedium"/>

这很难解决,所以我想在这里分享它,这样其他人就不必像我一样撕破头发了!

首先,为什么标题文本首先会改变大小?我不确定,但我猜应用程序的主题以 'scaled pixel' 为单位指定文本大小,这意味着如果屏幕配置发生变化,实际文本大小可能会发生变化。所以我认为这是有意为之的行为。

我使用的示例布局有点愚蠢,因为它有一个未使用的 TextView,正如@Ruan_Lopes 指出的那样。这完全没有必要,因为无论如何我都可以使用 alertDialog.setMessage(textPrompt) 来更改对话框的消息。事实上,使用 Android Device Monitor 中的 Layout Hierarchy Viewer 显示用户的布局无论如何都插入到消息下方。

层次结构查看器还向我展示了警告对话框标题的高度和宽度实际上并没有改变,即使文本确实缩小了!所以为标题设置TextView的高度或宽度并没有解决文本收缩问题。

最后,当对话框首次显示时,我记录了标题的文本大小(以像素为单位),然后每当我更新对话框标题的文本时,都使用相同的值来设置文本大小。因为我还想在设备旋转时保留文本大小,所以我选择将文本大小保存在 onSaveInstanceState(Bundle outState) 中。但如果您不介意屏幕旋转时标题文字大小不同,则不必这样做。

注意 TextView.getTextSize() returns a value in pixels so you have to use the correct units when calling TextView.setTextSize(int, float).

这是最终代码。除了删除 TextView 并将其替换为 EditText 之外,我没有更改布局 xml,尽管这在这里没有区别。

package com.world.test.fixshrinkingdialogtitletext;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class ChangeTitleDialogFragment
        extends DialogFragment {

    private static final String DIALOG_TITLE = "DIALOG_TITLE";
    private static final String TEXT_PROMPT = "TEXT_PROMPT";
    private static final String POSITIVE_BUTTON_TEXT = "POSITIVE_BUTTON_TEXT";
    private static final String SCREEN_COUNT = "SCREEN_COUNT";
    private static final String TITLE_TEXT_SIZE = "TITLE_TEXT_SIZE";

    private String dialogTitle = null;
    private String textPrompt = null;
    private String positiveButtonText = null;
    private int screenCount;
    private float titleTextSize;

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

        if (savedInstanceState == null) {
            screenCount = 1;
            dialogTitle = "First screen";
            textPrompt = "Click continue";
            positiveButtonText = "Continue";
            titleTextSize = -1;
        } else {
            dialogTitle = savedInstanceState.getString(DIALOG_TITLE);
            textPrompt = savedInstanceState.getString(TEXT_PROMPT);
            positiveButtonText = savedInstanceState.getString(POSITIVE_BUTTON_TEXT);
            screenCount = savedInstanceState.getInt(SCREEN_COUNT);
            titleTextSize = savedInstanceState.getFloat(TITLE_TEXT_SIZE);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putString(DIALOG_TITLE, dialogTitle);
        outState.putString(TEXT_PROMPT, textPrompt);
        outState.putString(POSITIVE_BUTTON_TEXT, positiveButtonText);
        outState.putInt(SCREEN_COUNT, screenCount);
        outState.putFloat(TITLE_TEXT_SIZE, titleTextSize);
    }

    @Override
    @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        LayoutInflater inflater = getActivity().getLayoutInflater();
        @SuppressLint("InflateParams")
        final View view = inflater.inflate(R.layout.dialog, null);
        builder.setView(view);
        builder.setTitle(dialogTitle);
        builder.setMessage(textPrompt);
        builder.setPositiveButton(positiveButtonText, null);
        builder.setNegativeButton("Cancel", null);

        AlertDialog dialog = builder.create();

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {

            @Override
            public void onShow(final DialogInterface dialog) {
                final AlertDialog alertDialog = (AlertDialog) dialog;

                final int alertTitleId = getActivity().getResources().getIdentifier( "alertTitle", "id", "android" );
                final TextView titleTV = (TextView)alertDialog.findViewById(alertTitleId);
                if (titleTextSize < 0) {
                    // Then user has launched this dialog directly from the calling activity.
                    titleTextSize = titleTV.getTextSize(); // Units = pixels!
                } else {
                    // Use the existing value we saved when the configuration changed:
                    titleTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextSize);
                }

                final Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                okButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        if (screenCount == 3) {
                            dismiss();
                        } else {
                            screenCount++;

                            textPrompt = "Blah blah blah blah blah blah blah blah";
                            alertDialog.setMessage(textPrompt);

                            dialogTitle = "Screen Number " + screenCount;
                            alertDialog.setTitle(dialogTitle);

                            titleTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextSize);

                            if (screenCount == 3) {
                                positiveButtonText = "OK";
                                okButton.setText(positiveButtonText);
                            }
                        }
                    }
                });
            }
        });

        return dialog;
    }
}