12

我有一个显示框字符的自定义字体。我使用的字体显然不支持所有语言。我想检查我要显示的字符串是否可以通过我的自定义字体显示。如果不能,那么我想使用标准的 Android 字体(我知道它可以显示字符)。我找不到检查我的字体是否可以显示特定字符​​串的方法。我确信我已经在某处看到了一种方法。有人知道吗?

4

7 回答 7

8

更新: 如果您正在为 API 级别 23 或更高级别进行编码,请使用Orson Baines的回答中提到的Paint.hasGlyph()。否则请参阅下面的原始答案。


正如您在自己的答案中提到的那样,没有可用于检查的内置方法。但是,如果您对要检查的字符串/字符有一定的控制权,则实际上可以使用更具创造性的方法来做到这一点。

您可以绘制一个您知道要检查的字体中缺少的字符,然后绘制一个您想知道它是否存在的字符,然后最后比较它们,看看它们是否相同。

这是一个代码示例,说明了我如何实现此检查:

public Bitmap drawBitmap(String text){
    Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ALPHA_8);
    Canvas c = new Canvas(b);
    c.drawText(text, 0, BITMAP_HEIGHT / 2, paint);
    return b;
}

public byte[] getPixels(Bitmap b) {
    ByteBuffer buffer = ByteBuffer.allocate(b.getByteCount());
    b.copyPixelsToBuffer(buffer);
    return buffer.array();
}
public boolean isCharacterMissingInFont(String ch) {
    String missingCharacter = "\u0978"; // reserved code point in the devanagari block (should not exist).
    byte[] b1 = getPixels(drawBitmap(ch));
    byte[] b2 = getPixels(drawBitmap(missingCharacter));
    return Arrays.equals(b1, b2);
}

使用此方法需要牢记一些重要的限制:

  • 您检查的字符(对 的参数isCharacterMissing)必须是非空格(可以使用Character.isWhitespace()检测)。在某些字体中,缺失的字符会呈现为空白,因此如果您比较存在的空白字符,则会错误地将其报告为此类字体中的缺失字符。
  • missingCharacter成员必须是已知在要检查的字体中缺失的字符。我正在使用的代码点U+0978是天城文 Unicode 块中间的保留代码点,因此当前所有 Unicode 兼容字体中都应该缺少它,但是将来当新字符添加到 Unicode 时,这个代码点可能分配给一个真实的角色。所以这种方法不是未来的证明,但如果您自己提供字体,您可以确保在更改应用程序字体时使用丢失的字符。
  • 由于这个检查是通过绘制位图并比较它们来完成的,所以它不是很有效,所以它应该只用于检查应用程序中的几个字符而不是所有字符串。

更新:

正如其他人指出的那样,查看 U+0978 的解决方案并没有奏效。该字符是在2014 年6 月的Unicode 7.0版本中添加的。另一种选择是使用存在于 unicode 中但不太可能用于普通字体的字形。

早期王朝楔形文字块中的U+124AB可能是许多字体中根本不存在的东西。

于 2014-03-27T05:49:00.743 回答
8

从 Android 版本 23 开始,您可以像这样测试它:

Typeface typeface;
//initialize the custom font here

//enter the character to test
String charToTest="\u0978";
Paint paint=new Paint();
paint.setTypeface(typeface);
boolean hasGlyph=paint.hasGlyph(charToTest);
于 2016-05-03T04:46:10.757 回答
3

please check the source code from Googles Mozc project. The EmojiRenderableChecker class seems to work pretty well!

it's like a compat version for Paint.hasGlypgh (added in Marshmallow).

于 2016-12-12T12:22:49.983 回答
2

@nibarius 的回答效果很好,但字符不同:“\u2936”。

但是,该解决方案在内存、cpu 和时间方面都很繁重。我需要一个针对极少数字符的解决方案,所以我通过只检查边界来实现一个“快速而肮脏”的解决方案。它的工作速度大约快 50 倍,因此更适合我的情况:

public boolean isCharGlyphAvailable(char... c) {
      Rect missingCharBounds = new Rect();
      char missingCharacter = '\u2936';
      paint.getTextBounds(c, 0, 1, missingCharBounds); // takes array as argument, but I need only one char.
      Rect testCharsBounds = new Rect();
      paint.getTextBounds(c, 0, 1, testCharsBounds);
      return !testCharsBounds.equals(missingCharBounds);
}

我应该警告说,这种方法不如@nibarius 准确,并且存在一些误报和误报,但如果您只需要测试几个字符以便能够回退到其他字符 - 这个解决方案很棒。

于 2015-05-07T23:55:34.143 回答
2

对于那些仍然希望您的应用程序与低于 23 的 API 兼容并且仍然在代码中使用 hasGlyph 函数的人,您可以通过以下方式使用 @TargetApi(23):

@TargetApi(23)
public boolean isPrintable( String c ) {
    Paint paint=new Paint();
    boolean hasGlyph=true;
    hasGlyph=paint.hasGlyph(c);
    return hasGlyph;
}

然后在您的代码中:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if(isPrintable(yourString)) {
        //Do Something
    }
}

唯一的问题是在低于 23 的 API 中,您的应用可能会显示空白符号。但至少在 API23+ 中,您的应用程序将是完美的。

于 2017-12-08T09:47:00.267 回答
1

要检查音乐符号♫是否显示在字符串中(如果在某些设备上没有显示),您可以尝试测量字符串宽度;if width == 0然后符号不存在。

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Rect rtt = new Rect();
paint.getTextBounds( "♫", 0, 1, rtt );
    if( rtt.width() == 0 ){
}
于 2017-12-05T17:34:34.193 回答
0

使用PaintCompat.hasGlyphwhich 依赖Paint.hasGlyph于 API 版本 23 及更高版本,但对较旧的 Android 版本具有向后兼容的实现。

于 2022-01-25T01:00:02.327 回答