Как Внедрить Что-То Своё В Координаторлайаут И Не Умереть: Путь Android-Самурая

Привет! Меня зовут Андрей Шоколов, я Android-разработчик в компании KODE. Компания «Форвард Лизинг» обратилась к нам с просьбой разработать мобильное приложение на основе готового дизайна.

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

За основу мы решили взять координаторLayout: у нас уже был положительный опыт работы с ним на другом проекте.

Наша команда тоже часто любила посоревноваться, какой Layout лучше — КоординаторLayout или MotionLayout, и сейчас самое время это выяснить.

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

В статье я расскажу, с какими 7 трудностями я столкнулся при работе с Координатором и как это сделать за полчаса то, над чем я возился уже несколько дней.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая



Цель проекта

Мне нужно было создать AppBarLayout с дугой, которая прокручивалась бы в одну строку.

Функционал добавлен в существующую Активность приложения Форвард. В качестве корневого элемента для основного Activity был выбран координаторLayout — это ViewGroup, целью которого является координация внутренних элементов представления.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Главный экран мобильного приложения Форвард Лизинг Прежде чем я расскажу вам, что такое координаторLayout и с какими трудностями я столкнулся при реализации, я покажу вам, как это должно было получиться в итоге: Конечный результат

Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая



Что такое координаторLayout с поведением по умолчанию

КоординаторLayout — это обычный FrameLayout. Нет, извините: как написано в документации, это сверхмощный FrameLayout!

Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Основной особенностью координатораLayout является его поведение по умолчанию.

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

Думаю, все видели эти красивые анимации, когда Snackbar всплывает снизу, а вместе с ним поднимается вверх FAB (Floating Action Button).

Все работает идеально.

Но именно Behaviors я настрою позже, потому что когда нужно сделать не все по умолчанию, а добавить что-то свое, то возникают некоторые трудности.

Для реализации такой дуги был создан класс RoundedAppBarLayout, наследуемый от AppBarLayout.

Что дано в RoundedAppBarLayout

  • Панель инструментов — это наиболее распространенный вид панели инструментов Android.
  • ContentView, где может быть что угодно.

  • Дуга — это наша дуга.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая



С какими трудностями я столкнулся и как я их решил?



№1. Прокрутка

У нас есть RoundedAppBarLayout, который содержит панель инструментов, ContentView и Arc. Для каждого элемента представления внутри него можно установить ScrollFlags, которые описывают поведение представления при прокрутке: прокрутка, привязка,expandAlways,expandAlwaysCollapsed,exitUntilCollapsed. Как они работают? AppBarLayout перебирает все имеющиеся у него дочерние представления и смотрит: если установлена прокрутка, то добавляем, что это представление будет прокручиваться, если noScroll — возвращаемся.

Если на панели инструментов указано «Прокрутка», она будет прокручиваться, а все, что находится под ней, — нет. Соответственно, если поставить прокрутку на Toolbar и ContentView, то будут прокручиваться только они.

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



Решение

Сворачивающаяся панель инструментов.

Это позволяет вам оставить панель инструментов вверху и дает вам возможность прокручивать ContentView, Arc и контент ниже.

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

  
  
  
  
  
  
  
  
  
   

<Эxml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android " xmlns:app="http://schemas.android.com/apk/res-auto " xmlns:tools="http://schemas.android.com/tools " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/transparent " tools:parentTag="com.google.android.material.appbar.AppBarLayout "> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsingToolbar " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/transparent " app:layout_scrollFlags="scroll|snap|exitUntilCollapsed "> </com.google.android.material.appbar.CollapsingToolbarLayout> </merge>



№2. Прозрачные зоны в Дуге и рисовании дуг

Чтобы нарисовать дугу в AppBarLayout, блок Arc должен содержать зоны, которые будут прозрачными.

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

Но если мы оставим CollapsingToolbar, вложенный в AppBar, без цвета, как наш ContentView, то на выходе мы получим прозрачный прямоугольник.



Решение

Закрасьте панель инструментов CollapsingToolbar в какой-нибудь цвет. Мы выбрали фиолетовый, так как это основной цвет проекта.

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

Как это выглядит

Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Вопрос остается с дугой.

Мы не можем поместить его в CollapsingToolbar, потому что у него свой цвет, а Arc должна быть прозрачной.

Получается, что мы должны разместить дугу в AppBarLayout, но, как мы помним, она не позволяет нам прокручивать всё, что находится ниже.



Решение

Рисуйте на холсте и, прокручивая, придумайте, как нарисовать дугу.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

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

Элемент необходимо добавить в CollapsingToolbar. Можно было бы сразу добавить сюда Toolbar, но так как он должен быть последним элементом в CollapsingToolbarLayout, то его придется писать отдельно.

То есть я делаю макет Inflate и добавляю в конец CollapsingToolbarLayout. Код

private fun addContentView(){ if (childCount > 1) { val contentChild = this.getChildAt(1) removeView(contentChild) val layoutParams = CollapsingToolbarLayout.LayoutParams(contentChild.layoutParams) with(contentChild) { layoutParams.setMargins( marginStart, marginTop + toolbarHeight, marginEnd, marginBottom ) } contentChild.setBackgroundColor(context.getColor(R.color.accent2)) contentChild.layoutParams = layoutParams collapsingToolbar.addView(contentChild) } } override fun onFinishInflate() { super.onFinishInflate() addContentView() val toolbar = LayoutInflater.from(context) .

inflate(R.layout.toolbar_default, collapsingToolbar, false) removeView(toolbar) collapsingToolbar.addView(toolbar) }

В результате у нас получился вот такой простой класс, у которого есть атрибуты title, где можно задать иконку для Панели инструментов, добавить ContentView, который находится в самом нашем RoundedAppBarLayout, и нарисовать дугу.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Доступные методы

№3. Пустое место после ContentView

С чем вы столкнулись дальше? После Toolbar и ContentView у нас нет места.

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

Я заранее ожидал такого поведения.



Решение

Расширение AppBarLayout. Я также сохраняю appbarBottom для рисования дуги: сохраняю нижнюю координату ContentView и увеличиваю AppBarLayout до конца блока Arc. Так нам будет легче рисовать.

(Спойлер: это решение сыграет со мной злую шутку.

) Расширение AppBarLayout

class RoundedAppBarLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppBarLayout(context, attrs, defStyleAttr) { init { LayoutInflater.from(context).

inflate(R.layout.appbar_rounded_default, this, true) initView() } private fun initView() { this.post { layoutParams = CoordinatorLayout.LayoutParams(width, height + arcHeight) appbarBottom = height.toFloat() appbarHalfWidth = width / 2f } } }

Добавляю ContentChild и Toolbar для нормального отображения контента

override fun onFinishInflate() { super.onFinishInflate() if (childCount > 1) { val contentChild = this.getChildAt(1) removeView(contentChild) val layoutParams = CollapsingToolbarLayout.LayoutParams(contentChild.layoutParams) with(contentChild) { layoutParams.setMargins( marginStart, marginTop + toolbarHeight, marginEnd, marginBottom ) } contentChild.setBackgroundColor(context.getColor(R.color.accent2)) contentChild.layoutParams = layoutParams collapsingToolbar.addView(contentChild) }

я рисую дугу

private fun drawArc(canvas: Canvas) { val scale = bottom / height.toFloat() arcPath.apply { reset() moveTo(0f, appbarBottom) quadTo( appbarHalfWidth, //divide by 2 due to arc drawing logic (appbarBottom + (arcHeight * 2)) * scale, width.toFloat(), appbarBottom ) } canvas.drawPath(arcPath, arcPaint).

apply { invalidate() } }

Нам нужно рассчитать расстояние, когда AppBarLayout полностью и не полностью прокручен.

То есть масштаб = 1 означает, что AppBarLayout полностью развернут, а масштаб = 0 означает, что он свернут. И рисую саму дугу.

Я тут наткнулся на очень интересную логику: если указать по координате y, что крайняя точка дуги должна быть на уровне 48 пикселей, то вершина этой точки будет на уровне 24 пикселей — в два раза меньше.

В итоге нужно умножать на два - решил я, не понимая причины.

Сейчас, пишу эту статью, я понимаю, что использовал функцию, рисующую не дугу, а кривую Безье.

И строится оно не через крайнюю точку, а посередине.

Вы можете использовать Дугу вместо Пути.

Реализация останется прежней, только без умножения на 2. Весь код класса AppBarLayout

class RoundedAppBarLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppBarLayout(context, attrs, defStyleAttr) { private var appbarBottom = 0f private var appbarHalfWidth = 0f //region toolbarArc private val arcHeight = DimensUtils.convertDpToPixel(48f, context) private val toolbarHeight = DimensUtils.convertDpToPixel(56f, context) private val arcPaint = Paint().

apply { color = context.getColor(R.color.accent2) style = Paint.Style.FILL isAntiAlias = true } private val arcPath = Path() //endregion init { LayoutInflater.from(context).

inflate(R.layout.appbar_default, this, true) initView() } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawArc(canvas) } override fun onFinishInflate() { super.onFinishInflate() if (childCount > 1) { val contentChild = this.getChildAt(1) removeView(contentChild) val layoutParams = CollapsingToolbarLayout.LayoutParams(contentChild.layoutParams) with(contentChild) { layoutParams.setMargins( marginStart, marginTop + toolbarHeight, marginEnd, marginBottom ) } contentChild.setBackgroundColor(context.getColor(R.color.accent2)) contentChild.layoutParams = layoutParams collapsingToolbar.addView(contentChild) } val toolbar = LayoutInflater.from(context) .

inflate(R.layout.toolbar_default, collapsingToolbar, false) removeView(toolbar) collapsingToolbar.addView(toolbar) } private fun initView() { setBackgroundColor(context.getColor(R.color.transparent)) outlineProvider = null this.post { layoutParams = CoordinatorLayout.LayoutParams(width, height + arcHeight) appbarBottom = height.toFloat() appbarHalfWidth = width / 2f } } private fun drawArc(canvas: Canvas) { val scale = bottom / height.toFloat() arcPath.apply { reset() moveTo(0f, appbarBottom) quadTo( appbarHalfWidth, //divide by 2 due to arc drawing logic (appbarBottom + (arcHeight * 2)) * scale, width.toFloat(), appbarBottom ) } canvas.drawPath(arcPath, arcPaint).

apply { invalidate() } } }



№4. Белая полоса при коллапсе

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

При прокрутке экрана буквально за пару пикселей до конца появляется белый прямоугольник.

Когда начинаешь его разбирать, понимаешь, что это трюки с поведением AppBarLayout. Так как я обновил ширину всего AppBarLayout (теперь есть AppBarLayout и ширина нашей дуги), то при его сворачивании Layout видит, что AppBarLayout должен быть той же высоты, что и Toolbar и дуга, поэтому он распределяет пространство ровно для этого размера.

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

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

Я не смог найти этого в коде AppBarLayout. Пожалуй, это тонкости работы с координаторомLayout.

Решение

Я долго думал, как это исправить, и решил воспользоваться методом «инкостализации».

Он заключается в том, что я пишу свой собственный Behavior, и когда он устанавливается в AppBarLayout, вызываю метод setRoundedAppBarBehavior. По сути, я просто добавляю дополнительное поле, чтобы оно могло отображаться поверх AppBarLayout. Код

class RoundedAppBarBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) { private var isInstalled = false override fun layoutDependsOn( parent: CoordinatorLayout, child: View, dependency: View ): Boolean { if (!isInstalled && dependency is BaseAppBarLayout) { isInstalled = true child.setRoundedAppBarBehavior() } return super.layoutDependsOn(parent, child, dependency) } } fun View.setRoundedAppBarBehavior() { if (this is ViewGroup) { val arcHeight = resources.getDimensionPixelSize(R.dimen.toolbar_arc_height) this.post { clipToPadding = false val lp = CoordinatorLayout.LayoutParams(layoutParams) lp.behavior = AppBarLayout.ScrollingViewBehavior() lp.setMargins(marginStart, marginTop - arcHeight, marginEnd, marginBottom) layoutParams = lp } } }

Все снова работает, ура! Как выглядит проблема и решение?

Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая



№ 5. AppBar не будет прокручиваться без контента

Оказалось, что каждый AppBarLayout может содержать внутри себя контент. А AppBarLayout думает: внутри меня нет контента, так зачем мне скроллить?

Решение

Разделение базового класса на два дочерних класса: RoundedAppBarLayout и SimpleRoundedAppBarLayout. В первый можно поместить контент, но второй останется без него.

Код базового класса AppBarLayout и двух унаследованных: SimpleRoundedAppBarLayout и RoundedAppBarLayout.

abstract class BaseAppBarLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppBarLayout(context, attrs, defStyleAttr) { var title: String? = null set(value) { field = value titleToolbar?.

text = value ?: "" } var navigationIcon: Int? = null var isEnableCollapsingBehaviour: Boolean = false // The value from which the arc is drawn protected var appbarBottom = 0f protected var appbarHalfWidth = 0f //region toolbarArc protected val arcHeight = context.resources.getDimensionPixelSize(R.dimen.toolbar_arc_height) protected val toolbarHeight = context.resources.getDimensionPixelSize(R.dimen.toolbar_height) val nonScrollableHeight = arcHeight + toolbarHeight protected val arcPaint = Paint().

apply { color = context.getColor(R.color.accent2) style = Paint.Style.FILL isAntiAlias = true } protected val arcPath = Path() //endregion var contentChild: View? = null override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawArc(canvas) } fun updateToolbarTitleMargin( marginStart: Int = 0, marginTop: Int = 0, marginEnd: Int = 0, marginBottom: Int = 0 ) { titleToolbar.layoutParams = Toolbar.LayoutParams(titleToolbar.layoutParams).

apply { setMargins(marginStart, marginTop, marginEnd, marginBottom) } } protected fun initToolbar(toolbar: Toolbar) { navigationIcon?.

let { toolbar.navigationIcon = ContextCompat.getDrawable(context, it) toolbar.setNavigationOnClickListener { (context as? Activity)?.

onBackPressed() } } toolbar.findViewById<TextView>(R.id.titleToolbar)?.

let { textView -> textView.text = title if (navigationIcon != null) { textView.layoutParams = Toolbar.LayoutParams(textView.layoutParams).

apply { setMargins(0, 0, 64.dp, 0) } } } } protected fun initAttrs(attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyle: Int = 0) { context.withStyledAttributes( attrs, R.styleable.RoundedAppBarLayout, defStyleAttr, defStyle ) { val defValue = -1 title = getString(R.styleable.RoundedAppBarLayout_ral_title) getResourceId(R.styleable.RoundedAppBarLayout_ral_navigate_icon, defValue).

apply { if (this != defValue) navigationIcon = this } isEnableCollapsingBehaviour = getBoolean(R.styleable.RoundedAppBarLayout_ral_collapsing_behaviour, false) } } protected open fun drawArc(canvas: Canvas) { val scale = (bottom - nonScrollableHeight) / (height - nonScrollableHeight).

toFloat() contentChild?.

alpha = max(0f, scale - (1 - scale)) if (isEnableCollapsingBehaviour) collapsingBehaviour(scale) arcPath.apply { reset() moveTo(0f, appbarBottom) quadTo( appbarHalfWidth, //multiply by 2 due to arc drawing logic appbarBottom + (arcHeight * 2) * scale, width.toFloat(), appbarBottom ) } canvas.drawPath(arcPath, arcPaint).

apply { invalidate() } } private fun collapsingBehaviour(scale: Float) { titleToolbar?.

alpha = 1 - scale contentChild?.

y = (toolbarHeight - arcHeight).

toFloat().

dp } } class SimpleRoundedAppBarLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : BaseAppBarLayout(context, attrs, defStyleAttr) { init { LayoutInflater.from(context).

inflate(R.layout.appbar_rounded_simple, this, true) initView() initAttrs(attrs, defStyleAttr) } override fun onFinishInflate() { super.onFinishInflate() toolbar.setBackgroundColor(ContextCompat.getColor(context, R.color.accent2)) initToolbar(toolbar) } override fun drawArc(canvas: Canvas) { val scale = (bottom - toolbarHeight) / (height - toolbarHeight).

toFloat() val startDrawingHeight = appbarBottom + arcHeight * (1 - scale) arcPath.apply { reset() moveTo(0f, startDrawingHeight) quadTo( appbarHalfWidth, //multiply by 2 due to arc drawing logic appbarBottom + (arcHeight * 2) * scale, width.toFloat(), startDrawingHeight ) } canvas.drawPath(arcPath, arcPaint).

apply { invalidate() } } private fun initView() { setBackgroundColor(context.getColor(R.color.transparent)) backgroundTintMode = PorterDuff.Mode.OVERLAY outlineProvider = null this.post { appbarBottom = height - arcHeight.toFloat() appbarHalfWidth = width / 2f } } } class RoundedAppBarLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : BaseAppBarLayout(context, attrs, defStyleAttr) { private var isArcDrawn = false init { LayoutInflater.from(context).

inflate(R.layout.appbar_rounded_default, this, true) initView() initAttrs(attrs, defStyleAttr) } override fun onFinishInflate() { super.onFinishInflate() if (childCount > 1) addContentView() val toolbar = LayoutInflater.from(context) .

inflate(R.layout.toolbar_default, collapsingToolbar, false) removeView(toolbar) collapsingToolbar.addView(toolbar) (toolbar as? Toolbar)?.

let { initToolbar(it) } } private fun initView() { setBackgroundColor(context.getColor(R.color.transparent)) backgroundTintMode = PorterDuff.Mode.OVERLAY outlineProvider = null this.post { layoutParams = CoordinatorLayout.LayoutParams(width, height + arcHeight) appbarBottom = height.toFloat() appbarHalfWidth = width / 2f isArcDrawn = true } } private fun addContentView() { val contentChild = this.getChildAt(1) removeView(contentChild) val layoutParams = CollapsingToolbarLayout.LayoutParams(contentChild.layoutParams) layoutParams.setMargins( marginStart, marginTop + toolbarHeight, marginEnd, marginBottom ) contentChild.setBackgroundColor(context.getColor(R.color.accent2)) contentChild.layoutParams = layoutParams this.contentChild = contentChild collapsingToolbar.addView(contentChild) } }

Панель инструментов, на которой нет содержимого, теперь можно раскрасить.

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

Здесь я показываю, как это было сделано в итоге.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Схема AppBar Здесь я уже мог добавить ArcView — сам вид дуги — и не переживать о том, что там не будет прозрачной дистанции.

Теперь CollapsingToolbar будет прозрачным, панель инструментов останется цветной, а AppBarLayout не требует расширения.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

Сравнение структур макета Единственное, что нам пришлось изменить в коде, это изменить высоту и переделать прорисовку дуги, поскольку поскольку Child там нет, то и затемнять ничего не нужно.

XML-код для SimpleRoundedAppBarLayout и RoundedAppBarLayout

<Эxml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android " xmlns:app="http://schemas.android.com/apk/res-auto " xmlns:tools="http://schemas.android.com/tools " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/transparent " android:orientation="vertical " tools:parentTag="com.google.android.material.appbar.AppBarLayout "> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsingToolbar " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/transparent " app:layout_scrollFlags="scroll|snap|exitUntilCollapsed "> <View android:id="@+id/arcView " android:layout_width="match_parent " android:layout_height="48dp " android:layout_marginTop="56dp " android:background="@color/transparent " /> <include android:id="@+id/toolbar " layout="@layout/toolbar_default" android:layout_width="match_parent " android:layout_height="56dp " android:layout_gravity="top " app:layout_collapseMode="pin " /> </com.google.android.material.appbar.CollapsingToolbarLayout> </merge> <Эxml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android " xmlns:app="http://schemas.android.com/apk/res-auto " xmlns:tools="http://schemas.android.com/tools " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/transparent " tools:parentTag="com.google.android.material.appbar.AppBarLayout "> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsingToolbar " android:layout_width="match_parent " android:layout_height="wrap_content " android:background="@color/accent2 " app:layout_scrollFlags="scroll|snap|exitUntilCollapsed "> </com.google.android.material.appbar.CollapsingToolbarLayout> </merge>



№6. При скрытии и показе AppBarLayout в активности появляется белая полоса

Далее у нас были последствия метода «инкостализации» при настройке видимости.

У нас одна деятельность и по ней много фрагментов.

Вверху активности находится RoundedAppBarLayout, а внизу — контейнер для фрагментов.

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

Причина в том, что в дочернем контейнере фрагмента было установлено поле.

Белая полоса – это тот самый край.



Как внедрить что-то своё в КоординаторЛайаут и не умереть: путь Android-самурая

При скрытии и показе AppBarLayout в активности появлялась белая полоса.



Решение

Завершите пользовательское поведение и добавьте к нему VisibilityListener. Новый код поведения

class RoundedAppBarBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) { private var isInstalled = false override fun layoutDependsOn( parent: CoordinatorLayout, child: View, dependency: View ): Boolean { if (!isInstalled && dependency is BaseAppBarLayout) { isInstalled = true child.setRoundedAppBarBehavior() addVisibilityListener(dependency, child) } return super.layoutDependsOn(parent, child, dependency) } private fun addVisibilityListener(appBarLayout: AppBarLayout, child: View) { var isVisibleSaved = appBarLayout.isVisible val visibilityListener = ViewTreeObserver.OnGlobalLayoutListener { if (isVisibleSa

Теги: #Android #Разработка Android #Разработка мобильных приложений #Kotlin #разработка Android #motionlayout #coordinatorlayout
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.