Как создавать кастомные LayoutManagers для Android

автор Михаил Гуревич

5 Июл 2016

В недавнем обновлении support библиотек Android появился новый компонент RecyclerView, который пришёл на замену ListView и принёс много новых возможностей. Он предназначен для создания больших комплексных списков и позволяет использовать различные LayoutManagers, в том числе и кастомные.

На одном из проектов нам потребовалось создать нетрадиционное представление списка. Так мы написали свои лейауты Carousel LayoutManager и Expand LayoutManager. Их подробное описание можно посмотреть на GitHub.

В этой статье мы хотим рассказать об основных принципах создания кастомных LayoutManagers. Реализация собственных лейаутов требует написания большого количества кода. Чтобы облегчить задачу, мы поделимся ключевыми моментами.

Пишем свой LayoutManager

К стандартным LayoutManagers относятся:

  • LinearLayoutManger – для классических списков
  • GridLayoutManager – для табличного вида
  • StaggeredGridLayoutManager – для композиции элементов в стиле Pinterest

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

Прежде чем создавать собственный LayoutManager, убедитесь, что вы знаете по каким принципам его создавать.

Общие правила создания кастомных лейаутов:

1. Рисовать только то, что отображается на экране.

2. Использовать быстрый алгоритм для вычисления позиций элементов, а не пробегать по всему списку из Adapter (RecyclerView.Adapter).

3. Лишний раз не инфлейтить views, которые уже есть на экране, а переиспользовать их.

4. Не вызывать requestLayout при каждом удобном случае. Вместо этого самим двигать вьюшки при необходимости. Например, когда надо сделать анимацию.

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

Методы для реализации лейаутов:

    • onLayoutChildren – самый главный метод, где происходит строительство элементов для отображения на экране

 

    • onMeasure – очень важный метод. Если размеры дочерних views в LayoutManager хоть как-то зависят от этого параметра, то важно его обнулить, пересчитать его размеры и заново пересчитать все дочерние views с нужными размерами.

 

    • scrollToPosition(int) – позволяет скроллить весь лейаут до определенной позиции в Adapter

 

    • smoothScrollToPosition(recyclerView, state, position) – анимированный скролл, который требует указать направление прокрутки списка и тип скорости анимации

 

    • canScrollVertically/canScrollHorizontal – отличный способ блокировки возможности скролла в отдельных направлениях

 

    • scrollVerticallyBy/scrollHorizontalBy – позволяет изменить состояние LayoutManager. Используя этот метод, необходимо проскроллить все его элементы и вернуть число, равное количеству сделанных скроллов. Например, можно вернуть 0, тогда это будет почти равнозначно запрету скороллинга в методах выше.

 

  • onSaveInstanceState/onRestoreInstanceState – помогает сохранять состояние кастомного LayoutManager, например, необходимо при переворотах

По сути, перечисленные методы отвечают за функции, которые выполняют лейауты. Например, наш ExpandLayoutManager позволяет отображать дополнительную информацию по каждому элементу списка. Использует разнообразные scrollBy, scrollHorizontallyBy для возможности скроллинга:

ExpandLayoutManager

Наш Carousel LayoutManager опять же задействует ScrollVerticallyBy и ScrollHorizontallyBy, чтобы прокручивать список разделов приложения. Он может работать циклично, то есть листать список бесконечно, а может и до определенного порога. Кроме этого, он поддерживает scrollToPosition и smoothScrollToPosition для возможности немедленного перехода на нужный элемент из кода:

Carousel LayoutManager

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

Определившись с методами и ключевыми принципами написания лейаутов, можно переходить к архитектуре.

Изучаем подход к архитектуре LayoutManagers

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

Например, для ExpandLayoutManager это mScrollOffset, mDecoratredChildHeight, mExpandItemPosition, mExecutingAnimationData. С помощью этих данных мы всегда можем отследить, в каком состоянии находится наш LayoutManager. Это нужно для того, чтобы суметь его восстановить при onLayoutChildren, scrollVerticallyBy/scrollHorizontalBy и для поддержки анимации.

2. Удалите ненужные вьюшки перед заполнением нужными. Это не значит, что надо удалять все views. Подразумевается удаление только тех, которые теперь стали невидимы.

3. Не создавайте новых views, если они уже добавлены в LayoutManager. Пройдитесь по всем его вьюшкам и найдите ту, которая сейчас необходима. Если такая вьюшка не была найдена, то создайте ее с помощью getViewForPosition, а потом снова привяжите ее к нужной позиции в лейауте с помощью bindViewToPosition.

Есть такая особенность, что контент в Adapter может быть изменен. Нужно вовремя ловить подобные ситуации, и когда элемент уже найден в списке дочерних вьюшек, заново вызвать на нем bindViewToPosition. В противном случае можно потерять изменения адаптера.

4. Ещё один метод state.didStructureChange вызывается, когда вы сдвинули, удалили или добавили элементы из середины списка. Он показывает происходящие изменения в лейауте.

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

Таким образом, с помощью кастомных LayoutManagers вы можете легко решать комплексные задачи по дизайну UI приложений на Android. В частности, добавлять разнообразные анимации как для вьюшек, так и для их контента. Если у вас есть вопросы по упомянутым примерам или вы хотели бы поделиться собственным опытом, оставляйте комментарии под статьей.

  • 0 Репосты

Комментарии

Фильтр

Закрыть

Технологии

Индустрии