2012-08-05 9 views
8

Ho un carattere personalizzato che sta visualizzando il carattere della casella. Il carattere che sto usando non supporta tutte le lingue apparentemente. Voglio verificare se la stringa che sto per visualizzare può essere visualizzata dal mio carattere personalizzato. Se non può, allora voglio usare il carattere standard di Android (che so può visualizzare i caratteri). Non riesco a trovare un metodo per verificare se il mio carattere tipografico può visualizzare una stringa particolare però. Sono sicuro di aver visto un metodo che lo fa da qualche parte. Qualcuno sa?Verificare se il carattere personalizzato può visualizzare il carattere

+0

Hmmmm ... Non penso che ci sia sufficiente accesso a caratteri di basso livello per determinare se un glifo particolare esiste in un particolare file di caratteri all'interno di Android. – CommonsWare

+0

La risposta di bahpo lo ha fatto per me: http://stackoverflow.com/a/41100873/5285687 – YellowJ

risposta

6

Aggiornamento: Se stai codifica per il livello di API 23 o superiore Si prega di utilizzare Paint.hasGlyph() come indicato nel answer by Orson Baines. Altrimenti vedi la mia risposta originale qui sotto.


Come hai detto nella tua risposta, non sono disponibili metodi incorporati per verificarlo. Tuttavia, se si ha il controllo su quale stringa/personaggio si desidera controllare, è effettivamente possibile farlo con un approccio leggermente più creativo.

È possibile disegnare un carattere che si sa manchi nel carattere che si desidera controllare e quindi disegnare un carattere che si desidera sapere se esiste, quindi confrontarli e vedere se sembrano uguali.

Ecco un esempio di codice che illustra come ho implementato questo controllo:

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); 
} 

Ci sono alcune limitazioni importanti da tenere a mente con questo metodo:

  • Il personaggio di controllare (argomento isCharacterMissing) deve essere uno spazio non bianco (può essere rilevato usando Character.isWhitespace()). In alcuni caratteri i caratteri mancanti sono resi come spazi bianchi, quindi se si confronta un carattere di spazio bianco che esiste sarebbe erroneamente riportato come carattere mancante in caratteri come questi.
  • Il membro missingCharacter deve essere un carattere noto come mancante nel tipo di carattere da controllare. Il punto di codice U+0978 che sto usando è un punto di codice riservato nel mezzo del blocco Unicode di Devanagari, quindi dovrebbe attualmente mancare in tutti i font compatibili con Unicode, tuttavia in futuro quando verranno aggiunti nuovi caratteri a Unicode questo punto di codice potrebbe essere assegnato a un personaggio reale. Quindi questo approccio non è a prova di futuro, ma se fornisci il font da solo puoi assicurarti di utilizzare un carattere mancante ogni volta che cambi il carattere della tua applicazione.
  • Poiché questo controllo viene eseguito disegnando bitmap e confrontandole non è molto efficiente, quindi dovrebbe essere usato solo per controllare alcuni caratteri e non tutte le stringhe nell'applicazione.

Aggiornamento:

La soluzione di guardare U + 0978 non ha funzionato a lungo come sottolineato da altri. Quel personaggio è stato aggiunto nella versione Unicode 7.0 in June 2014. Un'altra opzione è quella di usare un glifo che esiste in unicode, ma è molto improbabile che venga usato in un font normale.

U+124AB nel blocco Early Dynastic Cuneiform è probabilmente qualcosa che non esiste in molti tipi di carattere.

+2

magazzino Nexus 4 ha un glifo per "\ u0978". Invece, "\ u2936" sembra che manchi ancora. – auval

+0

Cosa dovrei usare per 'BITMAP_WIDTH'? –

+0

Qualcosa di abbastanza grande che ogni personaggio sia disegnato in modo diverso. Ad esempio, se provi a disegnare lettere diverse usando solo 2x2 pixel, molte lettere diverse probabilmente avranno lo stesso aspetto. Penso che avrei potuto usare qualcosa come 16 o 20. – nibarius

2

risposta @nibarius funziona bene, anche se con un carattere diverso: "\ u2936".

Tuttavia, questa soluzione è pesante in memoria, cpu e tempo. Avevo bisogno di una soluzione per un numero molto piccolo di caratteri, quindi ho implementato una soluzione "rapida e sporca" controllando solo i limiti. Funziona circa 50x volte più velocemente, quindi è più adatto per il mio caso:

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); 
} 

devo avvertirti che questo metodo è meno preciso @nibarius, e ci sono alcuni falsi negativi e falsi positivi, ma se solo è necessario testare alcuni caratteri per poter ricorrere ad altri personaggi: questa soluzione è ottima.

5

Come di Android versione 23, è possibile verificare in questo modo:

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); 
+0

Questa è la risposta giusta per API 23 e successive, IMO. – CrazyIvan1974

+1

Da JavaDoc: "Il controllo viene eseguito sull'intera catena di fallback, non solo sul riferimento immediato del carattere." Quindi, se vuoi solo sapere se è nel tipo di carattere che hai specificato, questo non funzionerà. – ashughes

1

si prega di controllare il codice sorgente da Googles Mozc progetto. La classe EmojiRenderableChecker sembra funzionare abbastanza bene!

è come una versione compat per Paint.hasGlypgh (aggiunta in Marshmallow).

0

Per verificare se il simbolo musicale ♫ viene visualizzato in una stringa (se non viene visualizzato su alcuni dispositivi), è possibile provare la larghezza della stringa measuring; if width == 0 quindi il simbolo è assente.

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
Rect rtt = new Rect(); 
paint.getTextBounds("♫", 0, 1, rtt); 
    if(rtt.width() == 0){ 
} 
1

Per quelli di voi che vorrebbe ancora la vostra applicazione per essere compatibile con le API inferiore a 23 e utilizzare ancora la funzione hasGlyph nel codice, è possibile utilizzare il @TargetApi (23) nel seguente modo:

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

E poi nel codice:

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

L'unico problema è che in API inferiore a 23, la vostra applicazione può mostrare simboli vuoti. Ma almeno in API23 + la tua app sarà perfetta.