Делаем textview прокручиваемым на android

Дополнительное чтение

Множественный выбор и щелчок для перехода (закрытая зона/2-й курс)

Полосатый ListView (BaseAdapter, значки) (закрытая зона/3-й курс)

Фильтруем базар. Поиск по списку (закрытая зона/3-й курс)

Фильтруем базар. Поиск по списку с помощью SearchView (закрытая зона/3-й курс)

Фильтруем базар. Поиск по тексту (Часть 1 и 2) (закрытая зона/3-й курс)

Фильтруем базар. Поиск по тексту, загруженному с сервера (XMLParser) (Часть 4) (закрытая зона/4-й курс)

Загружаем элементы списка из интернета (закрытая зона/3-й курс)

Используем RatingBar в списках (закрытая зона/3-й курс)

Список с разными типами разметки для каждого элемента списка (закрытая зона/5-й курс)

Разбиваем список на секции с заголовками (закрытая зона/5-й курс)

Показ большого текста

Если надо показать большой текст, то не стоит его сразу передавать в TextView. Иначе приложение может перестать плавно работать или вовсе начать зависать, так как будет делать много работы на главном потоке, чтобы показать огромный текст, который пользователь, возможно, даже и не прокрутит до конца. Решением будет разбиение текста на части (например, параграфы) и показ отдельных частей в RecyclerView. Для еще большего ускорения можно заранее рассчитывать размер блоков текста, используя PrecomputedText.

Для облегчения встраивания PrecomputedText в RecyclerView разработчики Google сделали специальные методы и :

Так как RecyclerView во время скролла создает новые элементы, которые еще не видны пользователю, то такое решение будет иметь достаточно времени для выполнения работы в фоне до того, как элемент будет показан пользователю.

Следует помнить, что после вызова метода нельзя менять стиль текста (например, поставить новый шрифт), в противном случае произойдет исключение, так как значения, с которыми вызывался , не будут совпадать с теми, которые окажутся в TextView.

Адаптеры — заполнение списка данными

Компоненту ListView требуются данные для наполнения. Источником наполнения могут быть массивы, базы данных. Чтобы связать данные со списком, используется так называемый адаптер.

Адаптер для стандартного списка обычно создаётся при помощи конструкции new ArrayAdapter(Context context, int textViewResourceId, String[] objects).

  • context — текущий контекст
  • textViewResourceId — идентификатор ресурса с разметкой для каждой строки. Можно использовать системную разметку с идентификатором android.R.layout.simple_list_item_1 или создать собственную разметку
  • objects — массив строк

Метод setAdapter(ListAdapter) связывает подготовленный список с адаптером.

Переходим к java-коду. Сначала мы получаем экземпляр элемента ListView в методе onCreate(). Далее мы определяем массив типа String. И, наконец, используем адаптер данных, чтобы сопоставить данные с шаблоном разметки. Выбор адаптера зависит от типа используемых данных. В нашем случае мы использовали класс ArrayAdapter.

Отступление

Если вы будете брать строки из ресурсов, то код будет таким:

А будет еще лучше, если вы воспользуетесь специально предназначенным для этого случая типом ресурса <string-array>. В файле res/values/strings.xml добавьте следующее:

И тогда в коде используйте для объявления массива строк:

Запустив проект, вы увидите работающий пример прокручиваемого списка. Правда, созданный список пока не реагирует на нажатия. Но при нажатии выбранный элемент выделяется цветным прямоугольником (в версии Android 2.3 был оранжевый, а в Android 4.0 — синий, потом был серый цвет и т.д.).

Использование span’ов в тексте

Для стилизованного текста во фреймворке есть два интерфейса: и (с неизменяемой и изменяемой разметкой соответственно) и три реализации: (неизменяемый текст), (неизменяемый текст) и (изменяемый текст).

Изменяемый текст Изменяемая разметка
SpannedString нет нет
SpannableString нет да
SpannableStringBuilder да да

, например, используется внутри , которому требуется изменять текст.

Добавить новый span к строке можно при помощи метода:

Через первый параметр передается span, затем указывается диапазон индексов в тексте. И последним параметром можно управлять, какое будет поведение span’а при вставке нового текста: будет ли span распространяться на текст, вставленный в начальную или конечную точки (если в середину вставить новый текст, то span автоматически применится к нему вне зависимости от значений флага).

Перечисленные выше классы различаются не только семантически, но и тем, как они устроены внутри: и используют массивы для хранения span’ов, а использует дерево интервалов.

Если провести тесты на скорость отрисовки текста в зависимости от количества span’ов, то будут такие результаты: при использовании в строке до ~250 span’ов и работают примерно с одинаковой скоростью, но если элементов разметки становится больше 250, то начинает проигрывать. Таким образом, если стоит задача применить стиль к какому-то тексту, то при выборе класса надо руководствоваться семантическими требованиями: будут ли строка и стили изменяемыми. Но если для разметки требуется больше 250 span’ов, то предпочтение надо всегда отдавать .

Обработка нажатий

Но пока приложение никак не реагирует на наши нажатия. Исправим ситуацию. Нам нужно знать, на каком пункте списка осуществляется нажатие. У ListActivity есть специальный метод для таких случаев — onListItemClick(). Начинайте вводить первые символы названия метода и студия предложит вам подходящий вариант. Нажмите Enter на предложенном варианте и у вас появится заготовка.

У метода четыре параметра. Самым интересным является третий параметр position, который указывает на номер выбранного пункта списка.

Осталось только прописать код для события — давайте выведем всплывающее сообщение, которое будет содержать позицию выбранного элемента списка.

Отсчёт позиций идёт с нуля, поэтому я прибавляю единицу к номеру позиции, чтобы получить информацию в привычном виде.

Замурчательно. Но хочется узнать не номер выбранного пункта, а сам текст. У списка ListView есть специальный метод getItemAtPosition(position), возвращающий объект для заданной позиции. Перепишем код.

В данном случае мы используем первый параметр l, который отвечает за родительский компонент ListView. Возвращаемый объект нужно преобразовать в строку.

В тех методах, у которых нет в параметрах ссылки на ListView, мы можем получить доступ к списку через метод активности getListView().

Запускаем программу и начинаем щёлкать по любой позиции списка — мы получим соответствующее сообщение. Вы можете использовать свой код — вызывать новое окно, проигрывать музыку и т.д.

Своя разметка

Когда в самом начале статьи я говорил, что для ListActivity не нужен шаблон activity_main.xml, то немножко лукавил. На самом деле вы можете подключить свой шаблон, но с одним условием — шаблон должен содержать элемент ListView с идентификатором @android:id/list.

Можно заново создать файл activity_main.xml, если вы его удалили, как вас просили, или файл с другим именем, например, activity_customlist.xml:

Я специально установил зелёный цвет для фона, чтобы вы поверили, что будет запускаться наш шаблон вместо системного, а TextView с системным идентификатором android:id/empty нужен для отображения текста, если список будет пустым. Осталось добавить строчку кода, который подключает шаблон:

Запустите проект и убедитесь, что загружается наш шаблон. Если вы зададите пустой массив, то вместо списка вы увидите TextView с текстом List is Empty.

Ещё раз напомню, что в стандартных списках отдельный его элемент представляет собой компонент TextView. Если вы хотите создать более сложную разметку с картинками, то вам надо изучить поближе ListView. Для этого на сайте есть отдельный раздел.

Что нужно знать, когда устанавливаешь текст в TextView

При вызове метода на самом деле внутри создается копия строки:

То есть если установить текст со span’ами в TextView, а затем попытаться изменить переданный в объект, то в отображении ничего не произойдет.

Как видно из кода, новый объект создается при помощи фабрики. В TextView имеется возможность заменить фабрику, используемую по-умолчанию, на свою реализацию. Это может быть полезно, чтобы не делать лишних копирований строк. Для этого пишем фабрику, возвращающую тот же объект, и устанавливаем ее в TextView через сеттер :

При установке текста надо не забывать делать вызов , чтобы происходило обращение к нашей фабрике.

Разработчики Google советуют использовать это решение для отображения текста со span’ами в RecyclerView, чтобы уменьшить потребление ресурсов нашим приложением.

Если текст уже установлен в TextView, и надо добавить новый span, то совсем не нужно делать повторный вызов . Надо просто взять текст из TextView и добавить в него новый span. TextView автоматически слушает spannable-строку на добавление новых span’ов, и перерисовывается:

Если же у нас есть span, который стоит в тексте у TextView, то можно обновить значения его параметров и заставить TextView перерисоваться. Если новое изменение не затрагивает размер текста, достаточно вызвать , в противном случае – :

Прокрутка программным способом

определяет два метода: асинхронная прокрутка . Одна из перегрузок прокручивается до указанной позицией в , а другая Прокручивает указанный элемент в представление. Обе перегрузки имеют дополнительный аргумент, который можно использовать для указания, следует ли анимировать прокрутку.

Важно!

Эти методы не будут приводить к прокрутке, если свойство имеет значение .

Позицией в можно прокручивать до метода, принимающего аргументы и. При наличии вертикального объекта с именем в следующем примере показано, как выполнить прокрутку до 150 единиц, независимых от устройства, из верхней части .

Третьим аргументом для является аргумент, который определяет, отображается ли анимация с прокруткой при программной прокрутке .

Элемент в можно прокрутить на представление с помощью метода, принимающего аргументы и . В следующем примере показано, как прокручивать элемент в представлении по вертикали с именем и именем.

Третьим аргументом для является аргумент, который определяет, отображается ли анимация с прокруткой при программной прокрутке .

При прокрутке элемента в представлении точное расположение элемента после завершения прокрутки можно задать с помощью второго аргумента метода. Этот аргумент принимает член перечисления:

  • Указывает, что элемент должен быть прокручиваться до тех пор, пока он не будет виден в .
  • Указывает, что элемент должен быть прокручиваться до начала .
  • Указывает, что элемент должен быть прокручиваться по центру объекта .
  • Указывает, что элемент должен быть прокручиваться до конца .

Использование autoLink

В TextView есть возможность автоматического обнаружения ссылок. Для ее включения достаточно указать в разметке атрибут . При значении TextView во время установки нового текста найдет в нем все URL через регулярное выражение и установит на найденные диапазоны символов . Вот примерный код, как это происходит в SDK при вызове :

Так как это происходит на UI потоке, то не стоит использовать внутри элементов RecyclerView. В таком случае лучше вынести определение ссылок в фоновый поток. И здесь на помощь нам приходит класс :

У еще есть возможность указать значение – распознавание почтовых адресов (оно же будет включено при значении ). Эту возможность лучше вообще никогда не использовать. Проблема в том, что под капотом там будет создание экземпляра WebView, через который будет осуществляться поиск адреса! В исходном коде SDK в методе можно увидеть такую строку, этот код выполняется на главном потоке:

А внутри WebView стоит TODO от разработчиков SDK:

Но что же тогда использовать? Решением будет новая технология Smart Linkify, к сожалению доступная только начиная с Android P (28), которая работает на основе нейронных сетей и распознает различную информацию, в том числе и почтовые адреса. Вот небольшой пример использования:

В отличие старого Linkify, распознанные адреса не будут простыми ссылками. Над адресами при нажатии будет отображаться контекстный toolbar с возможными действиями, например показ адреса на Google карте.

Технология Smart Linkify способна распознавать различные данные: номера телефонов, авиарейсы и многое другое.

Magnifier

Начиная с Android P (28), появился новый элемент управления – Magnifier, который показывает увеличенные символы при выделении текста. С его помощью пользователю гораздо проще установить курсор на нужную позицию.

По умолчанию он работает в TextView, EditText и WebView, но при желании его можно использовать при написании своих элементов пользовательского интерфейса: его API достаточно прост.

Заключение

В данной статье были опущены многие нововведения последних версий Android и смежные темы, заслуживающие отдельных статей, например:

  • работа со стилями и темами при отображении текста
  • работа со шрифтами
  • работа с классами, производными от TextView (например, EditText)

Если кому-то интересна одна из этих тем, рекомендую посмотреть презентацию с прошедшего Google I/O’19 “Best Practices for Using Text in Android”.

Бой с тенью

Чтобы оживить текст, можно дополнительно задействовать атрибуты для создания эффектов тени: shadowColor, shadowDx, shadowDy и shadowRadius. С их помощью вы можете установить цвет тени и ее смещение. Во время установки значений вы не увидите изменений, необходимо запустить пример в эмуляторе или на устройстве. В следующем примере я создал тень красного цвета со смещением в 2 пикселя по вертикали и горизонтали. Учтите, что для смещения используются единицы px (пиксели), единицы dp не поддерживаются.

Программный эквивалент — метод public void setShadowLayer (float radius, float dx, float dy, int color):

Создание ссылок автоматом

У TextView есть ещё два интересных свойства Auto link (атрибут autoLink) и Links clickable (атрибут linksClickable), которые позволяют автоматически создавать ссылки из текста.

При этом уже на этапе разработки вы увидите, что строка адреса сайта после слов Мой адрес: стала ссылкой. Если вы запустите приложение и нажмете на ссылку, то откроется браузер с указанным адресом. Вам даже не придется писать дополнительный код. Аналогично, если указать номер телефона (параметр phone), то запустится звонилка.

У ссылки есть интересная особенность — при длительном нажатии на ссылку появляется диалоговое окно, позволяющее скопировать ссылку в буфер обмена.

Цвет ссылки можно поменять через свойство Text color link (XML-атрибут textColorLink), а программно через метод setTextLinkColor().

Программно можно установить ссылки на текст через класс Linkify:

В таких случаях придётся самостоятельно добавить ссылки в текстах. Например, определим ссылку в ресурсе:

Присвоим созданный ресурс тексту в TextView и запустим пример. Сам текст будет выглядеть как ссылка, но реагировать не будет. Чтобы исправить данную проблему, добавим код:

Ссылки в тексте выглядят не совсем удобными. Есть отдельная библиотека, которая улучшает функциональность. Описание проблем и ссылка на библиотеку есть в статье A better way to handle links in TextView — Saket Narayan.

Текст-подсказка

Веб-мастера знают о таком атрибуте HTML5 как placeholder, когда в текстовом поле выводится строчка-подсказка приглушенным (обычно серым цветом). Живой пример приведён ниже.

Подсказка видна, если текстовый элемент не содержит пользовательского текста. Как только пользователь начинает вводить текст, то подсказка исчезает. Соответственно, если удалить пользовательский текст, то подсказка появляется снова. Это очень удобное решение во многих случаях, когда на экране мало места для элементов.

В Android у многих элементов есть свойство Hint (атрибут hint), который работает аналогичным образом. Установите у данного свойства нужный текст и у вас появится текстовое поле с подсказкой.

Запускаем приложение и видим подсказку, которая исчезает при попытке ввести текст.

Выделить текст для копирования

По умолчанию, текст в TextView нельзя выделить для копирования. Но в API 11 появилась такая возможность, которая может пригодиться. Делается либо при помощи XML-атрибута android:textIsSelectable, либо через метод setTextIsSelectable().

Добавьте в разметку два компонента TextView и одно текстовое поле EditText для вставки скопированного текста. У первой текстовой метки установим возможность выделения текста декларативно.

Для второго компонента возможность выделения создадим программно.

Сделайте долгий тап на тексте в любом TextView. Увидите стандартные ползунки для выбора длины текста. Скопируйте текст, сделайте длинный тап в EditText и вставьте текст.

Ускорение показа текста

В 2015 году разработчики Instagram ускорили показ комментариев к фотографиям, используя глобальный кэш. Идея была в том, чтобы виртуально рисовать текст до показа его на экране, таким образом “разогрев” системный кэш. Когда подходила очередь показа текста, пользователь видел его гораздо быстрее, так как текст уже был измерен и лежал в кэше.

Начиная с Android P (28) разработчики Google добавили в API возможность выполнить фазу измерения размера текста заранее в фоновом потоке – (и бэкпорт для API начиная с Android I (14) — ). С использованием нового API в фоновом потоке будет выполнено 90% работы.

Пример:

Продолжаем изучать основы разработки приложений с использованием языка Kotlin.

Это уроки по основам разработки, и мы еще не дошли до собственно программирования на языке Kotlin, поскольку разработка приложений – это не только программирование. В этом уроке мы рассмотрим ресурсы приложения, а также создадим макеты для экранов приложения. Писать программные конструкции на языке Kotlin мы начнем в следующем уроке.

Как правило, каждый экран в вашем приложении для Android связан с одним классом Java или Kotlin, известным как Activity.  Этот термин можно перевести как активность или деятельность, но мы будем использовать термин активити,  без перевода. Единственный экран с отображенным «Hello World» создается с помощью активити  MainActivity.kt. Это активити было создано  средой разработки, когда вы создали свой новый проект. Каждое видимое активити в приложении для Android имеет макет, который определяет пользовательский интерфейс для активити. Android Studio имеет редактор макетов, в котором вы можете создавать и определять макеты.

Макеты описаны в XML. Редактор макета позволяет вам определять и изменять макет либо путем кодирования XML, либо с помощью интерактивного визуального редактора. Вы можете переключаться между редактированием макета в XML и в редакторе визуального дизайна и создавать макеты любым способом.

Скроллвиев в качестве корневого макета

Может иметь только один дочерний элемент, который может быть другими макетами. Поэтому, как правило, в качестве корневого макета страницы. Чтобы прокрутить его дочернее содержимое, вычислит разницу между высотой ее содержимого и ее собственной высотой. Это различие — это величина, на которую может прокручиваться содержимое.

Часто является дочерним элементом . В этом случае объект выдает значение, равное сумме значений высоты дочерних элементов. Затем объект может определить объем прокрутки его содержимого. Дополнительные сведения о веб-службе см. в разделе Xamarin.Forms StackLayout.

Внимание!

В вертикальном случае не устанавливайте для свойства значение , или . Это означает, что значение должно быть равно высоте по мере необходимости, что может равняться нулю. В то время как Xamarin.Forms защищается от этой ситуации, лучше избегать кода, который предполагает, что что-то не должно происходить.

Следующий пример XAML имеет в качестве корневого макета страницы:

В этом примере свойство имеет свой набор содержимого , который использует связываемый макет для вывода полей, определенных Xamarin.Forms . По умолчанию вертикальная прокрутка прокручивается, что открывает дополнительное содержимое:

Эквивалентный код на C# выглядит так:

Дополнительные сведения о макетах с возможностью привязки см Bindable Layouts in Xamarin.Forms . в разделе.

Динамическое заполнение списка

Рассмотрим пример динамического заполнения списка, когда список изначально пуст и пользователь сам добавляет новые элементы. Разместим на экране текстовое поле, в котором пользователь будет вводить известные ему имена котов. Когда пользователь будет нажимать на клавишу Enter на клавиатуре, то введённое имя кота будет попадать в список.

При нажатии на Enter мы получаем текст из текстового поля и заносим его в массив. А также оповещаем адаптер об изменении, чтобы список автоматически обновил своё содержание.

У нас получился каркас для чата, когда пользователь вводит текст и он попадает в список. Далее надо получить текст от другого пользователя и также добавить в список. К слову сказать, слово chat с французского означает «кошка». Но это уже совсем другая история.

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: