ui: fix liftOnScroll issues entirely

Make a hack layout that fixes the problem of the lift state not
actually following the RecyclerView state. This should remove the
need for all the fragile fixes for this UI idiom.
This commit is contained in:
OxygenCobalt 2021-08-30 06:43:18 -06:00
parent 047b885dca
commit 1251af660a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 87 additions and 26 deletions

View file

@ -78,19 +78,7 @@ class QueueDragCallback(
)
)
val result = clampedAbsVelocity * sign(viewSizeOutOfBounds.toDouble()).toInt()
recyclerView.post {
// CoordinatorLayout refuses to propagate a scroll event initiated by an item scroll,
// so we do it ourselves.
(appBar.layoutParams as CoordinatorLayout.LayoutParams).behavior
?.onNestedPreScroll(
coordinator, appBar, recyclerView,
0, result, tConsumed, 0
)
}
return result
return clampedAbsVelocity * sign(viewSizeOutOfBounds.toDouble()).toInt()
}
override fun onChildDraw(

View file

@ -107,7 +107,7 @@ class QueueFragment : Fragment() {
lastShuffle = isShuffling
binding.queueRecycler.scrollToPosition(0)
binding.queueAppbar.isLifted = false // Make sure lifted state changes.
// binding.queueAppbar.isLifted = false // Make sure lifted state changes.
}
}

View file

@ -144,12 +144,11 @@ class SearchFragment : Fragment() {
// TODO: Maybe find a better way to keep scroll state when the search
// results didn't actually change.
binding.searchRecycler.scrollToPosition(0)
binding.searchAppbar.isLifted = false
}
if (results.isEmpty()) {
binding.searchAppbar.setExpanded(true)
binding.searchRecycler.visibility = View.GONE
binding.searchRecycler.visibility = View.INVISIBLE
} else {
binding.searchRecycler.visibility = View.VISIBLE
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2021 Auxio Project
* CobaltCoordinatorLayout.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.ui
import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.annotation.StyleRes
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
/**
* An [AppBarLayout] that fixes a bug with the default implementation where the lifted state
* will not properly respond to RecyclerView events.
* TODO: Find a way to get the lift animation to not animate on startup.
*/
class LiftAppBarLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@StyleRes defStyleAttr: Int = -1
) : AppBarLayout(context, attrs, defStyleAttr) {
private var recycler: RecyclerView? = null
private val tConsumed = IntArray(2)
private val onPreDraw = ViewTreeObserver.OnPreDrawListener {
recycler?.let { rec ->
val coordinator = (parent as CoordinatorLayout)
(layoutParams as CoordinatorLayout.LayoutParams).behavior?.onNestedPreScroll(
coordinator, this, rec, 0, 0, tConsumed, 0
)
}
true
}
init {
viewTreeObserver.addOnPreDrawListener(onPreDraw)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// Assume there is one RecyclerView [Because there is]
recycler = (parent as ViewGroup).children.firstOrNull { it is RecyclerView }
as RecyclerView?
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
viewTreeObserver.removeOnPreDrawListener(onPreDraw)
}
}

View file

@ -8,7 +8,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
<org.oxycblt.auxio.ui.LiftAppBarLayout
android:id="@+id/detail_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -19,7 +19,7 @@
android:id="@+id/detail_toolbar"
style="@style/Widget.Toolbar.Icon" />
</com.google.android.material.appbar.AppBarLayout>
</org.oxycblt.auxio.ui.LiftAppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/detail_recycler"
@ -27,7 +27,8 @@
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:listitem="@layout/item_artist_header" />
tools:listitem="@layout/item_artist_header"
tools:layout_marginTop="56dp"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -12,7 +12,7 @@
android:background="?attr/colorSurface"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
<org.oxycblt.auxio.ui.LiftAppBarLayout
android:id="@+id/queue_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -26,7 +26,7 @@
app:navigationIcon="@drawable/ic_down"
app:title="@string/lbl_queue" />
</com.google.android.material.appbar.AppBarLayout>
</org.oxycblt.auxio.ui.LiftAppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/queue_recycler"

View file

@ -7,7 +7,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
<org.oxycblt.auxio.ui.LiftAppBarLayout
android:id="@+id/search_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -29,7 +29,7 @@
app:boxBackgroundMode="filled"
app:boxStrokeColor="?attr/colorAccent"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="2dp"
app:boxStrokeWidthFocused="@dimen/size_stroke_large"
app:endIconContentDescription="@string/desc_clear_search"
app:endIconDrawable="@drawable/ic_close"
app:endIconMode="clear_text"
@ -48,7 +48,7 @@
android:textCursorDrawable="@drawable/ui_cursor" />
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.appbar.AppBarLayout>
</org.oxycblt.auxio.ui.LiftAppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_recycler"

View file

@ -11,7 +11,7 @@
android:background="?attr/colorSurface"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
<org.oxycblt.auxio.ui.LiftAppBarLayout
android:id="@+id/settings_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -26,7 +26,7 @@
app:menu="@menu/menu_settings"
app:title="@string/set_title" />
</com.google.android.material.appbar.AppBarLayout>
</org.oxycblt.auxio.ui.LiftAppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_list_fragment"