Как установить пользовательский шрифт в AlertDialog с помощью библиотеки поддержки 26

Я использую версию 26.0.1 Android Support Library для установить пользовательские шрифты в моем приложении. В теме моего приложения я добавил:

<item name="android:fontFamily">@font/my_font</item>

Это сработало как шарм, преобразовав текст во всем моем приложении в мой собственный шрифт. ЗА ИСКЛЮЧЕНИЕМ моих диалогов - конкретно их заголовков, сообщений, а также их NumberPickers. В тех местах шрифты не обновлялись. (Радио-кнопки и флажки работали, как и кнопки да/нет)

Я что-то забыл добавить в свои темы или стили? Или это просто еще не поддерживается библиотекой поддержки?

Немного подробнее: я использую AppCompatDialogFragment для реализации всех своих диалогов. В их методах onCreateDialog() я создаю диалог, используя AlertDialog.Builder, а затем возвращаю его.

Спасибо за помощь!


person yuval    schedule 17.08.2017    source источник
comment
Я думаю, что это ошибка в библиотеке поддержки. На Android 26 это работает, если я укажу как android:fontFamily, так и app:fontFamily для моей основной темы. Ниже 26 шрифт заголовка диалога не меняется. Я протестировал версию библиотеки поддержки 27.0.2.   -  person devconsole    schedule 04.12.2017
comment
Добавьте его как задачу в Google IssueTracker – issuetracker.google.com   -  person HughHughTeotl    schedule 30.03.2018
comment
@devconsole Это все еще ошибка в библиотеке 26.0.1?   -  person Krish    schedule 02.05.2018
comment
Я думаю, что это рассматривается в этой проблеме: issuetracker.google.com/issues/70479266 статус говорит, что исправлено, но я еще не проверял.   -  person yuval    schedule 08.12.2018


Ответы (6)


Спасибо всем, кто ответил, но, к сожалению, ни одно из этих решений не сработало для меня. Я надеюсь, что они будут работать для кого-то еще.

Я пришел к выводу, что это ошибка в библиотеке поддержки, и, надеюсь, Google ее исправит. Тем временем я разработал этот хакерский обходной путь:

public static void applyCustomFontToDialog(Context context, Dialog dialog) {
    Typeface font = ResourcesCompat.getFont(context, R.font.my_font);
    if (font != null) {
        TextView titleView = dialog.findViewById(android.support.v7.appcompat.R.id.alertTitle);
        TextView messageView = dialog.findViewById(android.R.id.message);
        if (titleView != null) titleView.setTypeface(font, Typeface.BOLD);
        if (messageView != null) messageView.setTypeface(font);
    }
}

Это работает путем сканирования дерева представлений диалогового окна в поисках представлений заголовков и сообщений по идентификаторам, которые им дает библиотека поддержки. Если бы библиотека поддержки изменила эти идентификаторы, это больше не работало бы (вот почему это хакерство). Надеюсь, Google исправит эту проблему, и мне больше не понадобится это делать.

person yuval    schedule 07.12.2017
comment
какое хакерское решение :D - person andrea.rinaldi; 08.01.2018

Я нашел способ, который требует только однострочного изменения кода Java каждый раз, когда вы создаете AlertDialog.

Шаг 1

Создайте собственный повторно используемый макет, содержащий TextView с правильным набором шрифтов. Назовите его alert_dialog.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/SomeStyleWithDesiredFont"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/spacing_2x" />

Шаг 2

Создайте где-нибудь многоразовую вспомогательную функцию, которая раздует этот макет и установит текст в нужную строку.

public static TextView createMessageView(String message, Context context) {
    TextView messageView = (TextView) LayoutInflater.from(context).inflate(R.layout.alert_dialog, null, false);
    messageView.setText(message);
    return messageView;
}

Шаг 3

В каждой цепочке AlertDialog.Builder в вашем коде замените эту строку:

.setMessage(messageString)

с этой строкой:

.setView(createMessageView(messageString, context))

(Обратите внимание, что тот же подход должен работать для заголовка TextView. Вы можете применить собственное представление для заголовка, вызвав setCustomTitle() в вашем конструкторе)

person danwilkie    schedule 30.01.2018
comment
Спасибо! Я думаю, что это решение менее хакерское, чем мое :) - person yuval; 31.01.2018

Вы должны использовать ContextThemeWrapper при создании построителя диалогов. Как это

ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context, R.style.mystyle); 
AlertDialog.Builder builder = new AlertDialog.Builder(wrappedContext);

Если вы поддерживаете только SDK 11 и выше, вы можете использовать

ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context, R.style.mystyle); 
AlertDialog.Builder builder = new AlertDialog.Builder(wrappedContext, R.style.mystyle);
person lionscribe    schedule 17.08.2017
comment
Действительно ли это работает для вас с точки зрения установки fontFamily для заголовка предупреждения? Потому что для меня это не так. - person Mikhail; 07.07.2018
comment
@Mikhail Вы правильно определили стиль для диалога? См., например, stackoverflow.com/a/24560196/2661303. - person lionscribe; 08.07.2018
comment
Кажется, он не работает с диалоговыми окнами предупреждений о совместимости приложений. ваше решение о родном? - person Mikhail; 09.07.2018

Возможно, здесь дело не в этом, у меня была аналогичная проблема, и я обнаружил, что fontFamily не будет затронут с помощью AsyncLayoutInflater. Это также имеет место, если AlertDialog вложен в файл AsyncLayoutInflater. Мне пришлось преобразовать в обычный инфлятор макета, чтобы отображался пользовательский шрифт. Например,

Это не показало fontFamily, вызванное из TextView XML.

AsyncLayoutInflater inflater =new AsyncLayoutInflater(activity);
    inflater.inflate(R.layout.dialog, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
        @Override
        public void onInflateFinished(@NonNull View view, int resid, ViewGroup parent) {
            final TextView tv = view.findViewById(R.id.textview);
            tv.setText("Text with custom fontFamily called in XML, but won't work");
        }
});

Это действительно показало, что fontFamily вызывается из TextView XML.

final ViewGroup nullParent = null;
final View view = activity.getLayoutInflater().inflate(R.layout.dialog, nullParent);
final TextView tv= view.findViewById(R.id.textview);
tv.setText("Text with custom fontFamily called in XML, and will work");
person seekingStillness    schedule 27.01.2019

вы можете раздуть собственный макет в своем диалоговом окне следующим образом:

final android.support.v7.app.AlertDialog.Builder alertDialogBuilder = new android.support.v7.app.AlertDialog.Builder(context,
R.style.LimitAlertDialogStyle);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View alertLayout = layoutInflater.inflate(R.layout.date_layout, null);
TextView tv= (TextView) alertLayout.findViewById(R.id.tv);

Typeface fc=Typeface.createFromAsset(getAssets(),"fonts/FONT"); 
tv.setTypeface(fc); 
person masoud vali    schedule 17.08.2017

Вы можете использовать пользовательский Alert Dialog и установить шрифт с помощью Typeface. Взгляните на приведенный ниже фрагмент кода.

 AlertDialog dg = new AlertDialog.Builder(this).setMessage("Your Message").show();
 TextView tv = (TextView) dg.findViewById(android.R.id.message); // Your TextView of custom Alert Dialog
 Typeface fc=Typeface.createFromAsset(getAssets(),"fonts/FONT"); // This is your font file name.
 tv.setTypeface(fc); 
person Harshit Trivedi    schedule 17.08.2017