Как предотвратить сокращение текста заголовка диалога, когда положительный текст кнопки становится короче?
Я хочу создать 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?
Лучшее решение не будет включать явную настройку размера текста, потому что тогда, если я когда-нибудь изменю тему приложения позже, мне придется помнить об изменении размера текста заголовка в соответствии с темой во всех многоэкранных диалогах, таких как этот.
2 ответа
Это было трудно решить, поэтому я хочу поделиться этим здесь, чтобы другим не пришлось рвать на себе волосы, как я!
Во-первых, почему текст заголовка в первую очередь меняет размер? Я не знаю наверняка, но я предполагаю, что тема приложения определяет размер текста в единицах "масштабированного пикселя", что означает, что фактический размер текста может измениться, если изменится конфигурация экрана. Поэтому я думаю, что это намеренное поведение.
Макет примера, который я использовал, был немного глупым, потому что у него был неиспользуемый TextView, как указывал @Ruan_Lopes. Это совершенно не нужно, потому что я мог бы использовать alertDialog.setMessage(textPrompt)
в любом случае изменить сообщение диалога. Фактически, использование средства просмотра иерархии макетов в Android Device Monitor показало, что макет пользователя в любом случае вставляется под сообщение.
Средство просмотра иерархии также показало мне, что высота и ширина заголовка диалогового окна предупреждения фактически не менялась, даже когда текст уменьшался! Таким образом, установка высоты или ширины TextView для заголовка не устраняет проблему сжатия текста.
В конце я записал размер текста заголовка (в пикселях), когда диалоговое окно было впервые показано, а затем использовал это же значение для установки размера текста всякий раз, когда я обновлял текст заголовка диалога. Поскольку я также хотел сохранить размер текста при поворотах устройства, я решил сохранить размер текста в onSaveInstanceState(Bundle outState)
, Но вам не нужно этого делать, если вы не возражаете, что размер текста заголовка отличается от поворота экрана.
Обратите внимание, что TextView.getTextSize()
возвращает значение в пикселях, поэтому вы должны использовать правильные единицы при вызове TextView.setTextSize(int, float)
,
Вот окончательный код. Я не изменил макет XML, кроме как удалить TextView
и заменить его на EditText
хотя это не имеет значения здесь.
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;
}
}
Вы пытались установить minWidth на линейном макете?
ех.
<?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"/>