Mam niestandardową czcionkę, która wyświetla znak pola. Czcionka, której używam, najwyraźniej nie obsługuje wszystkich języków. Chcę sprawdzić, czy String, który mam zamiar wyświetlić, może być wyświetlany przez moją niestandardową czcionkę. Jeśli nie, to chcę użyć standardowej czcionki Androida (o której wiem, że może wyświetlać znaki). Nie mogę znaleźć metody sprawdzenia, czy moja czcionka może wyświetlić konkretny ciąg znaków. Jestem pewien, że widziałem metodę, która gdzieś to robi. Ktoś wie?Sprawdź, czy czcionka niestandardowa może wyświetlać znak
Odpowiedz
Aktualizacja: Jeśli kodująca poziom API 23 lub powyżej skorzystaj Paint.hasGlyph() jak wspomniano w answer by Orson Baines. W przeciwnym razie zobacz moją oryginalną odpowiedź poniżej.
Jak wspomniano we własnej odpowiedzi, nie ma wbudowanych metod dostępnych do sprawdzenia tego. Jeśli jednak masz jakąś kontrolę nad tym, który ciąg znaków/znaków chcesz sprawdzić, faktycznie można to zrobić z nieco bardziej kreatywnym podejściem.
Można narysować znak, którego nie ma w czcionce, którą chcesz sprawdzić, a następnie narysować znak, który chcesz wiedzieć, jeśli istnieje, a następnie porównać je i sprawdzić, czy wyglądają tak samo.
Oto przykład kodu, który pokazuje w jaki sposób realizowany ten test:
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);
}
Istnieją pewne istotne ograniczenia, aby pamiętać o tej metodzie:
- postać sprawdzeniu (argument
isCharacterMissing
) nie może być spacji (można go wykryć za pomocą Character.isWhitespace()). W niektórych czcionkach brakujące znaki są renderowane jako białe znaki, więc jeśli porówna się istniejący znak odstępu, zostanie błędnie zgłoszony jako brakujący znak w czcionkach takich jak te. - Członek musi być postacią, której brak w sprawdzanej czcionce. Punkt kodowy U+0978, którego używam, jest zarezerwowanym punktem kodowym w środku bloku kodu Unicode Devanagari, więc obecnie powinien być niedostępny we wszystkich czcionkach zgodnych z Unicode, jednak w przyszłości, gdy nowe znaki zostaną dodane do Unicode, ten punkt kodowy może zostać przypisany do prawdziwej postaci. Tak więc to podejście nie jest przyszłym dowodem, ale jeśli podasz font osobiście, możesz upewnić się, że używasz brakującego znaku za każdym razem, gdy zmieniasz czcionkę swojej aplikacji.
- Ponieważ to sprawdzenie odbywa się poprzez rysowanie bitmap i porównywanie ich nie jest zbyt wydajne, dlatego powinno być używane tylko do sprawdzania kilku znaków, a nie wszystkich ciągów w aplikacji.
Aktualizacja:
Rozwiązanie patrzeć U + 0978 nie działa długo, jak wskazano przez innych. Ta postać została dodana w wersji Unicode 7.0 w wersji June 2014. Inną opcją jest użycie glifu, który istnieje w Unicode, ale jest bardzo mało prawdopodobne, aby był używany w normalnej czcionce.
U+124AB w bloku Early Dynastic Cuneiform jest prawdopodobnie coś, co w ogóle nie występuje w wielu czcionkach.
stock Nexus 4 ma glif dla "\ u0978". Zamiast tego nadal brakuje "\ u2936". – auval
Co powinienem użyć dla 'BITMAP_WIDTH'? –
Wszystko wystarczająco duże, aby każda postać była rysowana inaczej. Na przykład, jeśli spróbujesz narysować różne litery używając tylko 2x2 pikseli, wiele różnych liter prawdopodobnie będzie wyglądać tak samo. Myślę, że mogłem użyć czegoś takiego jak 16 lub 20. – nibarius
Odpowiedź @nibarius działa dobrze, ale z innym charakterem: "\ u2936".
Jednak to rozwiązanie ma dużą pamięć, procesor i czas. Potrzebowałem rozwiązania dla bardzo małej liczby znaków, więc zaimplementowałem "szybkie i brudne" rozwiązanie, sprawdzając tylko granice. Działa około 50x razy szybciej, dzięki czemu jest bardziej odpowiednia dla mojego przypadku:
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);
}
muszę ostrzec, że ta metoda jest mniej dokładna niż @nibarius i istnieją pewne fałszywe negatywy i fałszywych alarmów, ale jeśli po prostu Aby przetestować kilka postaci, trzeba przetestować kilka postaci - to rozwiązanie jest świetne.
Począwszy od wersji Androida 23, można przetestować go tak:
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);
To jest właściwa odpowiedź dla API 23 i wyżej, IMO. – CrazyIvan1974
Z JavaDoc: "Sprawdzanie odbywa się na całym łańcuchu zapasowym, a nie tylko na bezpośrednim kodzie źródłowym." Więc jeśli chcesz tylko wiedzieć, czy jest to podana krój czcionki, to nie zadziała. – ashughes
proszę sprawdzić kod źródłowy ze Googles Mozc projektu. Klasa EmojiRenderableChecker wydaje się działać całkiem nieźle!
to jak wersja kompatybilna z Paint.hasGlypgh (dodana w Marshmallow).
Aby sprawdzić, czy symbol muzyki ♫ jest wyświetlany w łańcuchu znaków (jeśli nie jest wyświetlany na niektórych urządzeniach), można wypróbować measuring szerokość łańcucha; if width == 0
wtedy symbol jest nieobecny.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Rect rtt = new Rect();
paint.getTextBounds("♫", 0, 1, rtt);
if(rtt.width() == 0){
}
Dla tych z Was, którzy nadal lubi swoją aplikację za zgodną z API mniej niż 23 i nadal korzystać z funkcji hasGlyph w kodzie, można użyć @TargetApi (23) w następujący sposób:
@TargetApi(23)
public boolean isPrintable(String c) {
Paint paint=new Paint();
boolean hasGlyph=true;
hasGlyph=paint.hasGlyph(c);
return hasGlyph;
}
A potem w kodzie:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(isPrintable(yourString)) {
//Do Something
}
}
jedynym problemem jest to, że w niższych niż 23 API, aplikacja może pokazać puste symbole. Ale przynajmniej w API23 + Twoja aplikacja będzie idealna.
Hmmmm ... Nie sądzę, że mamy wystarczający dostęp do czcionek niskiego poziomu, aby określić, czy dany glif istnieje w konkretnym pliku czcionki z systemu Android. – CommonsWare
Odpowiedź bahpo zrobiła to dla mnie: http://stackoverflow.com/a/41100873/5285687 – YellowJ