在DialogFragment中更改ProgressDialog的字体类型

9

请问在DialogFragment中,是否可以更改ProgressDialog的消息显示字体类型?

public class LoadFromCloudTaskFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        this.progressDialog = new ProgressDialog(this.getActivity());
        this.progressDialog.setMessage(progressMessage);
        this.progressDialog.setCanceledOnTouchOutside(false);

        return progressDialog;
    }

通过继承ProgressDialog创建自定义类可能是其中一种方式。然而,我想知道是否有更好的替代方案?遗憾的是,我们没有ProgressDialog.Builder

我尝试过的其中一种替代方案是

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    this.progressDialog = new ProgressDialog(this.getActivity());
    this.progressDialog.setMessage(progressMessage);
    this.progressDialog.setCanceledOnTouchOutside(false);

    Utils.setCustomFont(this.progressDialog.findViewById(android.R.id.message), Utils.ROBOTO_LIGHT_FONT);

    return progressDialog;
}

但这会导致错误

android.util.AndroidRuntimeException: 添加内容之前必须调用requestFeature()

4个回答

4
Typeface font = Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf");
SpannableStringBuilder spannableSB = new SpannableStringBuilder(getString(R.string.text_please_wait));
spannableSB.setSpan (new CustomTypefaceSpan("fonts/Roboto-Regular.ttf", font), 0, spannableSB.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
loadDialog = ProgressDialog.show(this, null, spannableSB, true, false);

public class CustomTypefaceSpan extends TypefaceSpan {

    private final Typeface newType;

    public CustomTypefaceSpan(String family, Typeface type) {
       super(getContext(),family);
       newType = type;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
         applyCustomTypeFace(ds, newType);
    }

    @Override
    public void updateMeasureState(TextPaint paint) {
        applyCustomTypeFace(paint, newType);
    }

    private static void applyCustomTypeFace(Paint paint, Typeface tf) {
        int oldStyle;
        Typeface old = paint.getTypeface();
        if (old == null) {
            oldStyle = 0;
        } else {
            oldStyle = old.getStyle();
        }

        int fake = oldStyle & ~tf.getStyle();
        if ((fake & Typeface.BOLD) != 0) {
            paint.setFakeBoldText(true);
        }

        if ((fake & Typeface.ITALIC) != 0) {
            paint.setTextSkewX(-0.25f);
        }

        paint.setTypeface(tf);
    }
}

这对我来说完美地运作了。而且我做了相同的更改。 - Dinithe Pieris

3
从文档中可以看出: http://developer.android.com/reference/android/app/DialogFragment.html
public static class MyDialogFragment extends DialogFragment {
    static MyDialogFragment newInstance() {
        return new MyDialogFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.hello_world, container, false);
        View tv = v.findViewById(R.id.text);
        ((TextView)tv).setText("This is an instance of MyDialogFragment");
        return v;
    }
}

我猜您可以为DialogFragment提供自定义的布局XML。
之后,我会使用这个实用类来设置字体:
import java.util.Hashtable;
import java.util.Map;

import android.content.Context;
import android.graphics.Typeface;
import android.widget.TextView;

/**
 * Taken from bug on b.android.com
 * https://code.google.com/p/android/issues/detail?id=9904
 * <p>
 * Optimizes way to work with typefaces and avoids context related memory leak
 * */
public class Typefaces {

    private static final Map<String, Typeface> cache = new Hashtable<String, Typeface>();

    public static Typeface get(Context c, String name) {
        synchronized (cache) {
            if (!cache.containsKey(name)) {
                Typeface t = Typeface.createFromAsset(c.getAssets(),
                        String.format("fonts/%s.ttf", name));
                cache.put(name, t);
            }
            return cache.get(name);
        }
    }

    public static Typeface _default(Context c) {
        return get(c, "verdana");
    }

    public static void setFonts(Context c, TextView... tvs) {
        for (TextView t : tvs) {
            if (t != null)
                t.setTypeface(_default(c));
        }
    }

}

假设您使用 _default() 方法,需要将自定义字体放置在 assets/fonts/verdana.ttf 中。

我宁愿不提供自己的观点。我更喜欢使用默认的ProgressDialog,只需更改其字体类型。如果不行,我宁愿通过覆盖它来创建一个自定义的ProgressDialog类。 - Cheok Yan Cheng
@YanChengCHEOK 这是一个问题,因为不同的ROM和Android版本可能具有不同的布局和不同的TextView id。您需要使用反射API在已经膨胀的布局中查找所有TextView实例并设置字体。在我看来,使用自定义布局是最简单的方法。 - Marek Sebera

3

以下是一种建议的解决方案。但我认为这不是一个好的方式。欢迎提出更多建议。

public class ProgressDialogEx extends ProgressDialog {
    public ProgressDialogEx(Context context) {
        super(context);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = this.findViewById(android.R.id.message);
        if (view != null) {
            // Shouldn't be null. Just to be paranoid enough.
            Utils.setCustomTypeface(view, Utils.ROBOTO_LIGHT_FONT);
        }
    }
}

public class LoadFromCloudTaskFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        this.progressDialog = new ProgressDialogEx(this.getActivity());
        this.progressDialog.setMessage(progressMessage);
        this.progressDialog.setCanceledOnTouchOutside(false);

        return progressDialog;
    }

Utils.setCustomTypeface

public static final Typeface ROBOTO_LIGHT_TYPE_FACE = Typeface.createFromAsset(MyApplication.instance().getAssets(), "fonts/Roboto-Light.ttf");

public static void setCustomTypeface(View view, Typeface typeFace) {
    if (view instanceof TextView) {
        ((TextView)view).setTypeface(typeFace);
    } else if (view instanceof EditText) {
        ((EditText)view).setTypeface(typeFace);
    } else if (view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup)view;
        int count = viewGroup.getChildCount();
        for (int i = 0; i < count; i++) {
            setCustomTypeface(viewGroup.getChildAt(i), typeFace);
        }
    }
}

1
Utils activity 是什么? - Iman Marashi
请描述 Utils。 - nutella_eater

2
虽然这是一个老问题,但我已经整理了一些信息,可能会对未来的访问者有所帮助。
在我开始之前,这不是即兴设置。它只能在ProgressDialog初始化时完成,并且仅适用于内置字体。既然说了,让我们开始吧!首先,我们需要创建一个样式,其父级为android:Theme.Holo.Dialog,如下所示,在您的styles.xml文件中。
<style name="CustomFontDialog" parent="android:Theme.Holo.Dialog">
    <item name="android:typeface">monospace</item>
</style>

然后在你的初始化中添加一小段代码。
ProgressDialog prog = new ProgressDialog(new ContextThemeWrapper(context, R.style.CustomFontDialog)));

为了让这个答案尽可能地回答问题,我正在研究一个名为Calligraphy的库,并且根据问题的回复,开发人员计划将该功能添加到对话框中。Calligraphy可能最终是您想要使用的内容,但现在您必须使用非系统字体的自定义视图hack。无论如何,我希望这能帮助一些像我一样正在寻找答案的访客。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接