Як дізнатись, чи мій текстовий перегляд було багатократним?


78

У мене є багаторядковий, TextViewякий маєandroid:ellipsize="end" встановив. Однак я хотів би знати, якщо рядок, який я розміщу там, насправді занадто довгий (щоб я міг переконатися, що повний рядок відображається в іншому місці на сторінці).

Я міг би використати TextView.length()та дізнатись про те, яка приблизна довжина рядка буде відповідати, але оскільки це кілька рядків, TextViewдескриптори коли обертати, тому це не завжди буде працювати.

Будь-які ідеї?

Відповіді:


123

Ви можете отримати макет TextViewі перевірити кількість еліпсисів на рядок. Для кінцевого еліпсису достатньо перевірити останній рядок, наприклад:

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

Це працює лише після фази макетування, інакше повернутий макет буде нульовим, тому зателефонуйте йому у відповідне місце в коді.


7
Це не вдається, якщо ви вводите довгий текст без пробілів у останньому рядку вводу, щось на зразок "jashdkjashdkjashdkasjhdashdkasjdhkajsdhkasjdhakjshdksjahdaksjhdajkshdkajshdkjashdkjashdja". getEllipsisCount () у такому випадку поверне 0. Щоб це виправити, замість того, щоб перевіряти лише останній рядок, ви повинні прокрутити всі рядки та перевірити, чи повертає (l.getEllipsisCount (n)> 0) true; для всіх 0 <= n <рядків.
Тіаго

1
Через помилку getEllipsisCountфункції в API <= 14, вона не вдасться повернути 0, якщо текст містить спеціальні символи, такі як '\ n'. Тож ви можете обійти це, скориставшись бібліотеками підтримки та замінивши if (l.getEllipsisCount(lines-1) > 0)на if (l.getEllipsisCount(lines-1) > 0 || TextViewCompat.getMaxLines(this)).
Бам,

1
Тьфу, використовуйте дужки навіть для однорядкового висловлювання, якщо будь ласка
r3flss ExlUtr

@ r3flssExlUtr, і саме тому саме?
zarsky

Не могли б ви детальніше пояснити, що ви маєте на увазі під фазою розкладки. Ви маєте на увазі, коли макет роздувається, і чому це пізніше стає нульовим?
6rchid,

35

textView.getLayout - це шлях, але проблема в тому, що він повертає нуль, якщо макет не підготовлений. Використовуйте наведене нижче рішення.

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

Фрагмент коду для видалення слухача ( джерело ):

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

17
Не забувайте, removeOnGlobalLayoutListener()коли це вам більше не потрібно.
mmathieum

1
Додайте це, коли буде знайдено еліпсис: if (Build.VERSION.SDK_INT <16) {textview.getViewTreeObserver (). RemoveGlobalOnLayoutListener (this); } ще {textview.getViewTreeObserver (). removeOnGlobalLayoutListener (це); }
Даніель Вілсон,

17
Використовуйте view.post (), а не VTO! Це набагато простіше.
людина

Ще більше тьфу, використовуйте дужки навіть для однорядкового висловлювання ifs
r3flss ExlUtr

1. заданий макет класифікатора помилок не має супутнього об'єкта при використанні Layoutтипу In Kotlin . 2. getEllipsisCountфункція повернута 0 . будь ласка, допоможіть мені
NIKUNJ GADHIYA

32

Я думаю, що найпростішим рішенням цього питання є наступний код:

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

Цей код передбачає, що у вашому XML TextView встановлює maxLineCount:)


3
ледачий, але дієвий :-D
msamardzic

4
Тест не пройде, якщо встановлено будь-яке використання великих літер. Додайте виклики toLowerCase () до обох рядків.
Ярх,

1
Якщо ваш textView.getLayout () повертає нуль, тоді вам слід використовувати: final ViewTreeObserver vto = tv.getViewTreeObserver (); vto.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener () {@Override public void onGlobalLayout () {tv.getViewTreeObserver (). removeOnGlobalLayoutListener (this); if Layout layout = tv.get toString ()). equalsIgnoreCase (text))) {// еліпсоване} else {// НЕ еліпсоване}}});
Ройз,

4
Це потрібно зробити після того, як textView відтворить текст. textView.post (() -> {// зроби це тут})
Саріт NOB

Дивно, що довжина обох предметів однакова, але вони відрізняються від видимого.
Суфіан

6

Мені це вдалося:

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

врятував мій день, тому що ViewTreeObserver погано працює в RecyclerView
kilian eller

5

public int getEllipsisCount (int рядок) :

Повертає кількість символів, які потрібно еліпсисировать, або 0, якщо еліпсис не відбудеться.

Отже, просто зателефонуйте:

int lineCount = textview1.getLineCount();

if(textview1.getLayout().getEllipsisCount(lineCount) > 0) {
   // Do anything here..
}

Оскільки getLayout () не можна викликати до встановлення макета, використовуйте це:

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

І нарешті, не забудьте видалити removeOnGlobalLayoutListener, коли вам це потрібно.


Ви можете редагувати відповідь правильною. @FrancescoDonzello
amalBit

Можливо, код не є чудовим, але підхід - це точно. Це вирішило мою проблему з визначенням, чи текст еліпсований. Цей підхід дуже корисний, коли ви додаєте подання у вікно через диспетчер вікон.
Йорако Гонсалес

На жаль, здається, що якщо еліпсис трапляється прямо в порожньому рядку ("\ n"), він також повертає 0, що правильно, оскільки це відбувається в символі індексу 0. Тож у цьому випадку це, здається, не спосіб сказати ...
Ширі

3
lateinit var toggleMoreButton: Runnable
toggleMoreButton = Runnable {
  if(reviewTextView.layout == null) { // wait while layout become available
       reviewTextView.post(toggleMoreButton) 
       return@Runnable
  }
  readMoreButton.visibility = if(reviewTextView.layout.text.toString() != comment) View.VISIBLE else View.GONE
}
reviewTextView.post(toggleMoreButton)

Це типовий випадок:

  1. коментар у 'reviewTextView'
  2. коментар може бути згорнуто за деякими критеріями
  3. якщо коментар згорнувся, ви показуєте кнопку "readMoreButton"

Цю відповідь можна зробити більш корисною за допомогою короткого текстового пояснення коду
charleslparker

Треба сказати, це було коротко і точно, і воно було написано котліном.
Райкуд

3

Шлях Котліна:

textView.post {
   if (textView.lineCount > MAX_LINES_COLLAPSED) {
   // text is not fully displayed
   }
}

Фактично View.post()виконується після подання подання і запускатиме надану функцію


1

це працює на мене

if (l != null) {
    int lines = l.getLineCount();
     if (lines > 0) {
     for (int i = 0; i < lines; i++) {
     if (l.getEllipsisCount(i) > 0) {
      ellipsize = true;
      break;
     }
    }
   }
  }

1

Простий метод Котліна. Дозволяє android:ellipsizeі android:maxLinesвикористовувати

fun isEllipsized(textView: TextView, text: String?) = textView.layout.text.toString() != text

Привіт, я розумію, ви перетворили його на kotlin, але, схоже, вже є відповідь, яка робить точно те саме, що ви робили в Java. Наступного разу, можливо, ви зможете відредагувати існуючу відповідь або, можливо, запропонувати редагування у коментарі до відповіді, замість того, щоб додавати зовсім нову відповідь. Щасливого кодування !!
because_im_batman

0

Дійсно працюйте так, наприклад, щоб передати повні дані в діалогове вікно з елемента RecyclerView:

holder.subInfo.post(new Runnable() {
                @Override
                public void run() {
                    Layout l = holder.subInfo.getLayout();
                    if (l != null) {
                        final int count = l.getLineCount();
                        if (count >= 3) {
                            holder.subInfo.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    final int c = holder.subInfo.getLineCount();
                                    if (c >= 3) {
                                        onClickToShowInfoDialog.showDialog(holder.title.getText().toString(), holder.subInfo.getText().toString());
                                    }
                                }
                            });
                        }
                    }
                }
            });

0

Поєднуючи @Thorstenvv awnser з @Tiano fix, ось версія Kotlin:

val layout = textView.layout ?: return@doOnLayout
val lines = layout.lineCount
val hasLine = lines > 0
val hasEllipsis = ((lines - 1) downTo 0).any { layout.getEllipsisCount(it) > 0 }
if (hasLine && hasEllipsis) {
    // Text is ellipsized
}

0

У Kotlin ви можете використовувати наведений нижче код.

var str= "Kotlin is one of the best languages."
textView.text=str
textView.post {
val isEllipsize: Boolean = !textView.layout.text.toString().equals(str)

if (isEllipsize) {
     holder.itemView.tv_viewMore.visibility = View.VISIBLE
} else {
     holder.itemView.tv_viewMore.visibility = View.GONE
}    
}

0

Найкрасномовніше рішення, яке я знайшов (у Котліні), - це створення функції розширення на TextView

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

Це чудово, оскільки для цього не потрібно знати, що таке повний рядок, або турбуватися про те, скільки рядків TextViewвикористовується.

TextView.textце те, що він намагається показати, тоді як TextView.layout.textце те, що насправді відображається на екрані, тому, якщо вони різні, це, напевно, стає еліпсованим

Щоб використовувати його:

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

-1

Використання getEllipsisCountне працює з текстом, у якому є порожні рядки. Я використовував такий код, щоб він працював:

message.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {

            if(m.isEllipsized == -1) {
                Layout l = message.getLayout();
                if (message.getLineCount() > 5) {
                    m.isEllipsized = 1;
                    message.setMaxLines(5);
                    return false;
                } else {
                    m.isEllipsized = 0;
                }
            }
            return true;
        }
    });

Переконайтеся, що не встановлено a maxLineCountу вашому XML. Потім ви можете перевірити наявність lineCountкоду, і якщо він перевищує певне число, ви можете повернути значення false, щоб скасувати кресленняTextView та встановити підрахунок рядків, а також прапорець, щоб зберегти, чи довгий вигляд тексту, чи ні . У текстовому вікні знову буде намальовано правильний підрахунок рядків, і ви будете знати, еліпсований чи ні, з прапором.

Потім ви можете використовувати isEllipsizedпрапор, щоб робити все, що вам потрібно.


-1

створити метод всередині класу TextViewUtils

public static boolean isEllipsized(String newValue, String oldValue) {
    return !((newValue).equals(oldValue));
}

викликайте цей метод, коли це потрібно, наприклад:

        if (TextViewUtils.isEllipsized(textviewDescription.getLayout().getText().toString(), yourModelObject.getDescription()))
            holder.viewMore.setVisibility(View.VISIBLE);//show view more option
        else
            holder.viewMore.setVisibility(View.GONE);//hide 

але textView.getLayout () не може викликати до встановлення подання (макета).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.