如何让自定义Heebo字体在TextView中支持加粗或配置多字体?
Hey there! Let's fix that Heebo font bold issue you're dealing with. I’ve got two solid solutions for you—first the proper, official way to set up multiple font weights (this is the recommended approach), then the custom function approach you asked about.
Solution 1: Configure a Font Family (Recommended)
The root cause of your problem is that you’re only loading a single regular font file, so Android can’t find a bold variant to use when you set textStyle="bold". Setting up a font family tells Android which font files correspond to which weights, so it can automatically switch between them.
Here's how to do it:
Add all Heebo font files to your project
Create ares/fontdirectory (if it doesn’t exist already) and drop in yourheebo-regular.ttf,heebo-bold.ttf, and any other weight files (like light, medium) you have.Create a font family XML file
In theres/fontfolder, make a new file namedheebo_font_family.xmlwith this content:<?xml version="1.0" encoding="utf-8"?> <font-family xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Regular weight (400 is standard for regular) --> <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/heebo_regular" /> <!-- Bold weight (700 is standard for bold) --> <font android:fontStyle="normal" android:fontWeight="700" android:font="@font/heebo_bold" /> <!-- Add other weights here if you have them, e.g., 300 for light, 500 for medium --> </font-family>Use the font family in your TextView
- In XML:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Regular text here, and *this is bold text*" android:textStyle="bold" android:fontFamily="@font/heebo_font_family" /> - In Kotlin/Java:
// Load the font family val heeboFamily = ResourcesCompat.getFont(context, R.font.heebo_font_family) // Apply it to the TextView, with bold style textView.typeface = Typeface.create(heeboFamily, Typeface.BOLD)
- In XML:
Now when you set textStyle="bold" or use Typeface.BOLD, Android will automatically pull the heebo-bold.ttf file instead of sticking with regular.
Solution 2: Custom Function to Detect Bold Styles and Switch Fonts
If for some reason you can’t use a font family, you can write a function to check if the TextView is set to bold and load the corresponding font. This also works if you have mixed bold/regular text in a single TextView (using SpannableStrings).
Case 1: Whole TextView is bold (set via textStyle)
Use this function to check the TextView's style and load the right font:
fun applyHeeboFont(textView: TextView) { val context = textView.context // Check if the TextView is set to bold val isBold = textView.textStyle and Typeface.BOLD != 0 || textView.typeface?.isBold == true // Load the appropriate font val fontRes = if (isBold) R.font.heebo_bold else R.font.heebo_regular textView.typeface = ResourcesCompat.getFont(context, fontRes) }
Case 2: Mixed bold/regular text (SpannableString)
If you have parts of the text styled as bold (using StyleSpan), you’ll need to replace those spans with custom spans that use your Heebo bold font. Here’s how:
First, create a custom TypefaceSpan to apply your custom font:
class CustomHeeboSpan(private val typeface: Typeface?) : MetricAffectingSpan() { override fun updateDrawState(ds: TextPaint) { applyTypeface(ds) } override fun updateMeasureState(paint: TextPaint) { applyTypeface(paint) } private fun applyTypeface(paint: Paint) { val oldTypeface = paint.typeface val oldStyle = oldTypeface?.style ?: 0 // Keep existing styles like italic if present val fakeStyle = oldStyle and (typeface?.style?.inv() ?: 0) if (fakeStyle and Typeface.BOLD != 0) paint.isFakeBoldText = true if (fakeStyle and Typeface.ITALIC != 0) paint.textSkewX = -0.25f paint.typeface = typeface } }
Then use this function to process the TextView's text:
fun applyHeeboFontWithSpans(textView: TextView) { val context = textView.context val originalText = textView.text ?: return if (originalText !is Spannable) { // If it's not a Spannable, just apply the regular/bold font applyHeeboFont(textView) return } // Find all StyleSpan instances that are bold val boldSpans = originalText.getSpans(0, originalText.length, StyleSpan::class.java) .filter { it.style == Typeface.BOLD } for (span in boldSpans) { val start = originalText.getSpanStart(span) val end = originalText.getSpanEnd(span) val flags = originalText.getSpanFlags(span) // Replace the StyleSpan with our custom Heebo bold span val boldFont = ResourcesCompat.getFont(context, R.font.heebo_bold) originalText.setSpan(CustomHeeboSpan(boldFont), start, end, flags) originalText.removeSpan(span) } // Set the default font to regular for non-bold text textView.typeface = ResourcesCompat.getFont(context, R.font.heebo_regular) textView.text = originalText }
When to use this approach?
This is useful if you’re dealing with dynamic text that has inline bold styling, but keep in mind the font family method is more maintainable and aligns with Android's best practices.
内容的提问来源于stack exchange,提问作者Bar Kozlovski

