Skip to content

Android Views

Michael Bely edited this page Apr 29, 2024 · 27 revisions

Important

ВНИМАНИЕ!
ЭТОТ РАЗДЕЛ БОЛЬШЕ НЕ ПОДДЕРЖИВАЕТСЯ!
РОАДМАП ПЕРЕЕХАЛ В NOTION

RemoteViews
View, которая может отображаться в другом процессе. Поддерживает ограниченное количество виджетов. Используется для виджетов или уведомлений. Клики обрабатываются через PendingIntent

Animations

ValueAnimator
Представляет механизм для запуска анимаций, вычисления анимированных значений и установки их для целевых объектов

ObjectAnimator
Наследуется от ValueAnimator. Обеспечивает поддержку анимации свойств целевых объектов. Анимации можно создавать из кода и xml

ViewPropertyAnimator
Вызывается через View.animate(). Подходит для выполнения нескольких анимаций одновременно

TextView

PrecomputedText
Возможность выполнить все измерения текста в любом потоке. Добавлен в Android 9

fun TextView.setTextAsync(longString: String) {
    val params = this.textMetricsParams
    val ref = WeakReference(this)

    CoroutineScope.launch(Dispatchers.Default) {
        val precomputedText = PrecomputedText.create(longString, params)
        withContext(Dispatchers.Main) {
            ref.get()?.let { textView ->
                textView.text = precomputedText
            }
        }
    }
}

Spannable
Spannable – это интерфейс, характеризующий текст, который имеет стилистическую разметку. Например с помощью Spannable можно создать текст, часть которого окрашена в иной цвет. Метод Spannable.setSpan() принимает произвольный объект типа Object, который используется для разметки. Этот метод не бросает исключений. Классы, которые реализуют интерфейс Spannable, должны игнорировать неподдерживаемые объекты разметки. Пример: ForegroundColorSpan для изменения цвета текста

Compound Drawable
Это drawable, который можно добавить в TextView. Эффективнее, чем использовать LinearLayout

RecyclerView

RecyclerView
Улучшенная замена ListView. Bмеет более гибкий API, хороший дизайн, соответствует принципу единственной ответственности. Переиспользует viewholders при скролле. Разделяет хранение и отображение данных. Можно изменить UI в runtime с помощью LayoutManager. Логика анимаций вынесена в ItemAnimator

DiffUtil
Для оптимизации: метод areContentTheSame проверяет только те поля объекта, которые видны на экране

setHasFixedSize
Если true - никакой контент или дочерние view внутри RecyclerView не влияют на его высоту или ширину. Владея этой информацией, RecyclerView не выполнит лишние измерения

setHasStableIds
Если true - сообщает RecyclerView, что нужно ориентироваться, помимо позиций, ещё и на stableId элементов. Рекомендуется использовать stableId для каждого ViewHolder — это помогает RecyclerView переиспользовать view, если меняется список

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

RecycledViewPool
Позволяет обмениваться представлениями между несколькими RecyclerView

Чтобы не лагал скролл
• не выполнять тяжелые операции в onBindViewHolder()
• использовать DiffUtil вместо notifyDataSetChanged(), обновлять одну строку вместо отрисовки всего списка
• использовать RecycledViewPool для вложенных списков
• использовать ViewStub для ленивого создания view в случае, если нужно отобразить ошибку, вместо хранения в памяти целого view
• в XML использовать в , чтобы не добавлять лищние view в иерархию
• использовать VectorDrawable вместо тяжелых PNG и JPG, использовать nine-patch для background
• явно указывать размер view, если он фиксирован, чтобы не тратить ресурсы на вычисление
• использовать setHasFixedSize(), setHasStableIds(), setItemViewCacheSize()
• обновлять индикаторы через recyclerView.findViewHolderForAdapterPosition(), а не через DiffUtil

AdapterDataObserver
В методе onItemRangeInserted отслеживать загрузку списка


AdapterDelegates
Favor composition over inheritance for RecyclerView Adapters

FastAdapter
The bullet proof, fast and easy to use adapter library, which minimizes developing time to a fraction

ScrollView

ScrollView
NestedScrollView

fillViewport
Определяет, должно ли ScrollView растягивать свое содержимое для заполнения области просмотра

Constraintlayout

Constraintlayout
ViewGroup, которая позволяет гибко размещать и изменять размеры виджетов

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

Flow
Позволяет размещать виджеты, на которые есть ссылки, горизонтально или вертикально, подобно цепочке

chain
Группа виджетов, связанных друг с другом двунаправленными ограничениями

barrier
Ограничить view набором других view

baseline
Выровнять view по базовой линии текста

guideline
Добавить горизонтальную или вертикальную направляющую, по которой можно выровнять другие view

CoordinatorLayout

CoordinatorLayout
Сверхмощный FrameLayout. Предназначен для взаимодействия дочерних виджетов между собой, например: drawer layout, floatingactionbutton

View

Creating a View Class
View
ViewGroup
View Binding
How Android Draws Views

Как создать кастомную View?
Как реализовать метод View.onMeasure()?
Как реализовать метод View.onDraw()?
В чем разница между invalidate() и requestLayout()?
Как работает метод dispatchTouchEvent()?
Для чего нужен метод onInterceptTouchEvent()?
Для чего нужен метод View.forceLayout()?
Назовите основные MotionEvent Actions
Как Touch Event доставляется до таргет-view?

CustomView Android. Кольцевая диаграмма для отображения статистики

Save State
View сохраняет и восстанавливает свое состояние с помощью методов onSaveInstanceState() и onRestoreInstanceState()
• чтобы view сохраняло свое состояние при пересоздании activity нужно указать ей id

onAttachToWindow()
Вызывается, когда view прикрепляется к окну

onDetachedFromWindow()
Вызывается, когда view открепляется от своего окна

onMeasure()
Вызывается для определения требований к размеру этого view и всех его дочерних элементов
EXACTLY - родитель определил и передал точный размер view. View будет иметь этот размер независимо от того, какого размера view хочет быть
AT_MOST - родитель определил и передал верхнюю границу размера view. View может быть любого размера в пределах этой границы
UNSPECIFIED - у родителя нет предпочтений к размеру view, размер может быть произвольным. Иногда это значение используется лэйаутом при первом проходе для определения желаемых размеров каждой из view. После чего measure() вызывается еще раз, но уже с другим режимом

onLayout()
Вызывается, когда view должно назначить размер и позицию всем своим дочерним элементам

requestLayout()
Следует вызвать, когда изменилось что-то, что сделало макет view недейстивтельным. Необходимо вызывать реализацию суперкласса

onDraw()
Вызывается, когда view должен отрисовать свое содержимое

invalidate()
Вызывает перерисовку view. Результат вызова этого метода – асинхронный вызов onDraw(). Используется, когда нужно перерисовать view без изменения размеров, например, когда изменяется background color. Должен быть вызван из UI thread, для других потоков: postInvalidate()

forceLayout()
Аналогичен requestLayout() для каждого дочернего элемента, но без прохоида вверх по иерархии view. Исключает угрозу бесконечной рекурсии

ViewGroup

ViewGroup
View, которая может содержать дочерние view. Базовый класс для контейнеров FrameLayout, LinearLayout и других

onInterceptTouchEvent()
Позволяет перехватить ивент во ViewGroup и не отправлять его вниз по иерархии в таргет-view

dispatchTouchEvent()
Этот метод помогает доставить объект MotionEvent до View, которой он предназначен

ViewPager2

Передать currentItem как аргумент фрагменту

class PagerViewModel @AssistedInject constructor(
    @Assisted private val savedStateHandle: SavedStateHandle
): ViewModel() {
    val tabLiveData: LiveData<Int> = savedStateHandle.getLiveData<Int>("tab")
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel.tabLiveData.observe(viewLifecycleOwner) { tab ->
        view.post { binding.viewPager.setCurrentItem(tab, false) }
    }
}

companion object {
    fun create(tab: Int) = PagerFragment().apply {
        arguments = bundleOf("tab" to tab)
    }
}
Clone this wiki locally