93 votes

Comment puis-je savoir si ma fenêtre de texte a été elliptisée ?

Je dispose d'une ligne TextView qui a android:ellipsize="end" set. J'aimerais cependant savoir si la chaîne de caractères que j'y place est effectivement trop longue (afin de m'assurer que la chaîne complète est affichée ailleurs sur la page).

Je pourrais utiliser TextView.length() et trouver la longueur approximative de la ficelle qui rentrera, mais comme il s'agit de plusieurs lignes, la TextView gère le moment de l'emballage, donc cela ne fonctionnera pas toujours.

Des idées ?

138voto

Thorstenvv Points 2669

Vous pouvez obtenir la disposition de la TextView et vérifiez le nombre d'ellipses par ligne. Pour une ellipse de fin, il suffit de vérifier la dernière ligne, comme ceci :

Layout l = textview.getLayout();
if (l != null) {
    int lines = l.getLineCount();
    if (lines > 0)
        if (l.getEllipsisCount(lines-1) > 0)
            Log.d(TAG, "Text is ellipsized");
}

Ceci ne fonctionne qu'après la phase de mise en page, sinon la mise en page retournée sera nulle, donc appelez ceci à un endroit approprié dans votre code.

8 votes

Cela échoue si vous entrez un long texte sans espace sur la dernière ligne de votre entrée, quelque chose comme "jashdkjashdkjashdkasjhdashdkasjdhkajsdhkasjdhakjshdksjahdaksjhdajkshdkajshdkjashdkjashdja". getEllipsisCount() retournera 0 dans ce cas. Pour le corriger, au lieu de ne vérifier que la dernière ligne, il faut boucler toutes les lignes et vérifier si ( l.getEllipsisCount(n) > 0 ) return true ; for all 0 <= n < lines.

1 votes

En raison d'un bug dans getEllipsisCount dans l'API <= 14, elle échouera et renverra 0 si le texte contient des caractères spéciaux comme ''. \n '. Vous pouvez donc contourner le problème en utilisant les bibliothèques de support et en remplaçant if (l.getEllipsisCount(lines-1) > 0) avec if (l.getEllipsisCount(lines-1) > 0 || TextViewCompat.getMaxLines(this)) .

2 votes

Ugh, utilisez des parenthèses même pour les déclarations d'une seule ligne, s'il vous plaît.

38voto

Himanshu Virmani Points 990

TextView.getLayout est la solution mais le problème est qu'il renvoie null si le layout n'est pas préparé. Utilisez la solution ci-dessous.

 ViewTreeObserver vto = textview.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
           Layout l = textview.getLayout();
           if ( l != null){
              int lines = l.getLineCount();
              if ( lines > 0)
                  if ( l.getEllipsisCount(lines-1) > 0)
                    Log.d(TAG, "Text is ellipsized");
           }  
        }
    });

Extraits de code pour la suppression de l'écouteur ( source ) :

mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    public void onGlobalLayout() {
        scrollToGridPos(getCenterPoint(), false);
        mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);        
    }
});

17 votes

N'oubliez pas de removeOnGlobalLayoutListener() quand tu n'en as plus besoin.

1 votes

Ajouter ceci lorsque la taille de l'ellipse est trouvée : if (Build.VERSION.SDK_INT < 16) { textview.getViewTreeObserver().removeGlobalOnLayoutListener(this) ; } else{ textview.getViewTreeObserver().removeOnGlobalLayoutListener(this) ; }

18 votes

Utilisez view.post() plutôt que VTO ! C'est beaucoup plus simple.

36voto

Francesco Florio Points 789

Je pense que la solution la plus simple à cette question est le code suivant :

String text = "some looooong text";
textView.setText(text);
boolean isEllipsize = !((textView.getLayout().getText().toString()).equalsIgnoreCase(text));

Ce code suppose que dans votre XML, le TextView a défini un paramètre maxLineCount :)

3 votes

Paresseux mais efficace :-D

4 votes

Votre test échouera si une majuscule quelconque est définie. Ajoutez des appels toLowerCase() aux deux chaînes de caractères.

1 votes

Si votre textView.getLayout() renvoie null, vous devez utiliser : final ViewTreeObserver vto = tv.getViewTreeObserver() ; vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { tv. getViewTreeObserver().removeOnGlobalLayoutListener(this) ; Layout layout = tv.getLayout() ; if( !((layout.getText().toString()).equalsIgnoreCase(text))){ // ellipsized }else{ // NOT ellipsized }}) ;)

9voto

Cícero Moura Points 860

Cela a fonctionné pour moi :

textView.post(new Runnable() {
                        @Override
                        public void run() {
                            if (textView.getLineCount() > 1) {
                                //do something
                            }
                        }
                    });

0 votes

A sauvé ma journée, parce que ViewTreeObserver ne fonctionne pas bien dans RecyclerView

8voto

Matt Smith Points 522

La solution la plus éloquente que j'ai trouvée (en Kotlin) est de créer une fonction d'extension sur TextView

fun TextView.isEllipsized() = layout.text.toString() != text.toString()

C'est génial car il n'est pas nécessaire de savoir quelle est la chaîne complète ou de s'inquiéter du nombre de lignes de la chaîne. TextView utilise.

TextView.text est le texte complet qu'il essaie de montrer, alors que TextView.layout.text est ce qui est réellement affiché à l'écran, donc s'ils sont différents, ils doivent être elliptiques.

Pour l'utiliser :

if (my_text_view.isEllipsized()) {
    ...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X