Ellipsize — е механизъм за отрязване на текст, при който вместо пикселно отрязване на реда, в края или средата се добавя символ на многоточие (…), сигнализиращ на потребителя, че текстът не се побира в контейнера. Тази техника се използва в заглавия, бутони, списъци с контакти и всякакви UI компоненти с ограничена ширина. Според Google Material Design Guidelines, ellipsize е стандартно поведение за TextView и UILabel, поддържащо четири режима на отрязване: начало, среда, край и движещ се текст.
Основни точки
Ellipsize (от англ. ellipsis — многоточие) — е техника за показване на текст, който надвишава размерите на контейнера. Вместо просто отрязване на реда по границата (clip), ellipsize добавя символ на многоточие (Unicode U+2026), указвайки на потребителя наличието на скрито съдържание.
Терминът се е утвърдил в Android SDK, където свойството android:ellipsize определя поведението на TextView при препълване. На iOS аналогичната функционалност се нарича truncation (отрязване) и се управлява чрез NSLineBreakMode. В уеб се използва CSS свойството text-overflow със стойност ellipsis.
Основната цел на ellipsize е да информира потребителя, че текстът е съкратен. За разлика от пикселното отрязване, при което думата може да бъде разрязана наполовина, ellipsize гарантира четливост: многоточието се поставя след цяла дума или знак, без да я разкъсва. Това е в съответствие с принципите на Material Design и Human Interface Guidelines.
Използвайте ellipsize навсякъде, където ширината на контейнера е фиксирана, а дължината на текста е динамична: заглавия на статии, клетки на таблици, бутони с надписи, контакти в списък, галета и пътища на файлове.
В Android ellipsize се конфигурира чрез атрибута android:ellipsize в XML или метода setEllipsize() в код. Налични са четири режима, всеки от които определя от коя страна текстът ще бъде отрязан.
Режим END (по подразбиране в повечето случаи) отрязва края на реда и поставя многоточие в дясната част на контейнера. Режим START отрязва началото — многоточие вляво, видим текст вдясно. MIDDLE отрязва средата, оставяйки началото и края на реда видими. Режим MARQUEE — анимирано превъртане на текст, при което многоточието не се показва, а текстът циклично се превърта.
<!-- XML layout -->
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="Very long text that will be truncated"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true" />
<!-- Kotlin code -->
textView.setEllipsize(TextUtils.TruncateAt.MIDDLE)
Важно: ellipsize работи само в комбинация с maxLines или singleLine. Ако не ограничите броя редове, TextView ще расте на височина и ellipsize няма да се активира. От Android 8.0 (API 26) нататък, ellipsize поддържа многоредов режим с maxLines > 1 — многоточието се поставя в края на последния ред.
За програмно извикване използвайте TextUtils.TruncateAt с една от стойностите: END, START, MIDDLE, MARQUEE. Стойността NONE изключва ellipsize.
На практика END е подходящ за 90% от случаите — потребителите очакват текстът да е отрязан в края. MIDDLE се използва за пътища на файлове (напр. "/User/.../project/main.kt"), за да е видим краят на пътя. START — за имена с общ префикс (напр. "...@gmail.com").
На iOS аналогът на ellipsize е свойството lineBreakMode на класа UILabel (и NSTextContainer за UITextView). Налични са три режима на отрязване: .byTruncatingTail (край), .byTruncatingMiddle (среда) и .byTruncatingHead (начало).
Режим .byTruncatingTail съответства на android:ellipsize="end". Режим .byTruncatingHead — START, .byTruncatingMiddle — MIDDLE. Режим .byClipping — отрязва текст без многоточие, рядко използван в съвременните интерфейси. Режим .byCharWrapping — пренасяне по знаци без отрязване.
let label = UILabel()
label.text = "Дълъг текст, който не се побира в границите на етикета"
label.lineBreakMode = .byTruncatingMiddle
label.numberOfLines = 1
// NSAttributedString също поддържа lineBreakMode
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
В iOS truncation работи в комбинация с numberOfLines. Ако numberOfLines = 1, текстът се отрязва на един ред. Ако numberOfLines = 2 — на втория ред. UITextView използва NSTextContainer.lineBreakMode, който също поддържа и трите режима на отрязване.
Особеност на iOS: режим .byTruncatingMiddle на UILabel може да се държи неочаквано на кратки редове — ако редът се побира напълно, многоточието не се появява. За гарантирано показване на многоточие на кратки редове използвайте персонализирана логика чрез sizeThatFits.
В уеб ellipsize се реализира чрез CSS свойството text-overflow: ellipsis в комбинация с overflow: hidden и white-space: nowrap. Това е стандартният начин за отрязване на ред с многоточие в уеб интерфейсите.
.text-cell {
width: 250px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
Свойството text-overflow не работи без overflow: hidden — браузърът трябва да знае, че съдържанието се отрязва. white-space: nowrap забранява пренасянето на реда, иначе текстът ще премине на следващия ред и препълване няма да настъпи.
За многоредово отрязване (напр. 2 реда с многоточие в края на втория) преди се използваше експерименталното свойство -webkit-line-clamp, което сега е стандартизирано като line-clamp в CSS Overflow Level 4.
На практика text-overflow: ellipsis се поддържа от всички съвременни браузъри от над 10 години и е най-надеждният начин за отрязване на текст в уеб.
Изборът на режим ellipsize влияе на UX и може както да подобри възприятието на интерфейса, така и да обърка потребителя. Основно правило: потребителят очаква отрязаната част да е там, където е най-малко необходима за разбиране.
Режим END е подходящ за заглавия, етикети, имена — потребителят вижда началото на реда и разбира контекста. Многоточието вдясно означава „има продължение, но не се е събрало“. Това е най-интуитивният и разпространен режим.
Режим MIDDLE е незаменим за пътища на файлове, имейл адреси и дълги идентификатори. Когато краят на реда съдържа уникална информация (име на файл, домейн), потребителят трябва да вижда точно нея, а началото може да бъде съкратено. Пример: "/User/.../important_document.pdf" — веднага се вижда името на файла.
Режим START се използва рядко, но е полезен за списък с контакти с общ префикс — например "...@gmail.com" вместо "username@gmail.com", когато всички адреси принадлежат на един домейн. Този модел обаче по-често обърква, отколкото помага. Според Nielsen Norman Group, потребителите четат отляво надясно и очакват важна информация в началото, следователно START отрязването увеличава когнитивното натоварване.
Режим MARQUEE (движещ се текст) е подходящ само за едноредови елементи с ниска честота на обновяване: текущ трак в плейъра, новинарски тикер, статусна лента. Не използвайте marquee в таблици, списъци или формуляри — анимацията разсейва и намалява производителността на слаби устройства.
Първи проблем — ellipsize не работи. Най-често причината е липсата на ограничение на броя редове. Без maxLines TextView расте на височина и не настъпва препълване по ширина. Решение: винаги посочвайте maxLines (или singleLine="true" за един ред).
Втори проблем — многоточието не се показва при програмна промяна на текст. След извикване на setText() TextView може да не се прерисува правилно. Решение: извикайте invalidate() или post(() -> requestLayout()) след промяна на текста.
Трети проблем — различно поведение на различни версии на Android. Преди API 23 ellipsize в многоредов режим (maxLines > 1) не се поддържаше. Решение: за съвместимост проверявайте Build.VERSION.SDK_INT и използвайте ViewCompat.setEllipsize() от AndroidX.
Четвърти проблем — символът на многоточие не се показва в персонализирани шрифтове. Ако шрифтът не съдържа глиф U+2026, многоточието се заменя с три точки. Решение: проверете шрифта за наличие на ellipsis глиф или добавете резервен шрифт чрез fontFamily.
Често задавани въпроси
Да, maxLines или singleLine е задължителен. Без ограничение на броя редове TextView ще се разшири на височина и отрязването няма да се активира.
Ellipsize добавя многоточие на мястото на прекъсване, информирайки потребителя за скрит текст. Clip просто отрязва текста по границата без никакъв индикатор.
Стандартният text-overflow: ellipsis отрязва след цяла дума. За отрязване в средата на дума използвайте overflow-wrap: break-word или JavaScript решение с измерване на ширина.
Да, чрез свойството textContainer.lineBreakMode в NSTextContainer. По подразбиране UITextView използва .byWordWrapping; променете на .byTruncatingTail/Middle/Head за отрязване.
Извикайте textView.setEllipsize(null) или textView.setEllipsize(TextUtils.TruncateAt.NONE). След това текстът ще се пренася, а не отрязва.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също