ui: switch to inset-based bottom sheet content

Do not do a measure + inset method with BottomSheetContentBehavior,
instead, try to re-apply window insets to adapt with the bar instead.

This fixes a lot of view clipping issues that made motion transitions
non-ideal and prevented a rounded playback bar. Only remaining issue is
RecyclerView instances, which need to be further reworked to resolve
scroll issues and edge effect problems.
This commit is contained in:
OxygenCobalt 2022-08-06 09:21:20 -06:00
parent 913db88fde
commit 0474940ee3
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
7 changed files with 35 additions and 47 deletions

View file

@ -2,6 +2,12 @@
## dev
#### What's Improved
- Improved bottom sheet code to prevent clipping issues
#### What's Fixed
- Fixed incorrect font being used in the queue title
## 2.6.0
#### What's New

View file

@ -22,7 +22,6 @@ import android.util.AttributeSet
import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.annotation.AttrRes
import androidx.core.view.updatePadding
import org.oxycblt.auxio.util.systemBarInsetsCompat
/**
@ -37,12 +36,9 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
clipToPadding = false
}
override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets {
return onApplyWindowInsets(insets)
}
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
updatePadding(bottom = insets.systemBarInsetsCompat.bottom)
// Save a layout by simply moving the view bounds upwards
translationY = -insets.systemBarInsetsCompat.bottom.toFloat()
return insets
}
}

View file

@ -22,7 +22,10 @@ import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.ui.AuxioSheetBehavior
import org.oxycblt.auxio.util.getDimen
/**
* The coordinator layout behavior used for the playback sheet, hacking in the many fixes required
@ -33,6 +36,9 @@ class PlaybackSheetBehavior<V : View>(context: Context, attributeSet: AttributeS
AuxioSheetBehavior<V>(context, attributeSet) {
init {
isHideable = true
if (Settings(context).roundMode) {
sheetBackgroundDrawable.setCornerSize(context.getDimen(R.dimen.size_corners_medium))
}
}
// Hack around issue where the playback sheet will try to intercept nested scrolling events

View file

@ -130,7 +130,7 @@ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHe
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean =
) =
playbackModel.moveQueueDataItems(
viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)

View file

@ -18,7 +18,6 @@
package org.oxycblt.auxio.ui
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.LayerDrawable
import android.os.Build
import android.util.AttributeSet
@ -73,12 +72,12 @@ abstract class AuxioSheetBehavior<V : View>(context: Context, attributeSet: Attr
child.apply {
// Sometimes the sheet background will fade out, so guard it with another
// colorSurface drawable to prevent content overlap.
background =
LayerDrawable(
arrayOf(
ColorDrawable(
context.getAttrColorCompat(R.attr.colorSurface).defaultColor),
sheetBackgroundDrawable))
val guardDrawable =
MaterialShapeDrawable(sheetBackgroundDrawable.shapeAppearanceModel).apply {
fillColor = context.getAttrColorCompat(R.attr.colorSurface)
}
background = LayerDrawable(arrayOf(guardDrawable, sheetBackgroundDrawable))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Shadows aren't disabled by default, do that.

View file

@ -24,6 +24,7 @@ import android.view.WindowInsets
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.bottomsheet.NeoBottomSheetBehavior
import kotlin.math.abs
import kotlin.math.max
import org.oxycblt.auxio.util.coordinatorLayoutBehavior
import org.oxycblt.auxio.util.replaceSystemBarInsetsCompat
import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -62,15 +63,7 @@ class BottomSheetContentBehavior<V : View>(context: Context, attributeSet: Attri
if (consumed != lastConsumed) {
lastConsumed = consumed
val insets = lastInsets
if (insets != null) {
child.dispatchApplyWindowInsets(insets)
}
lastInsets?.let(child::dispatchApplyWindowInsets)
measureContent(parent, child, consumed)
layoutContent(child)
return true
}
@ -85,21 +78,19 @@ class BottomSheetContentBehavior<V : View>(context: Context, attributeSet: Attri
parentHeightMeasureSpec: Int,
heightUsed: Int
): Boolean {
val dep = dep ?: return false
val behavior = dep.coordinatorLayoutBehavior as NeoBottomSheetBehavior
val consumed = behavior.calculateConsumedByBar()
if (consumed == Int.MIN_VALUE) {
return false
}
val contentWidthSpec =
View.MeasureSpec.makeMeasureSpec(parent.measuredWidth, View.MeasureSpec.EXACTLY)
val contentHeightSpec =
View.MeasureSpec.makeMeasureSpec(parent.measuredHeight, View.MeasureSpec.EXACTLY)
measureContent(parent, child, consumed)
child.measure(contentWidthSpec, contentHeightSpec)
return true
}
override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
super.onLayoutChild(parent, child, layoutDirection)
layoutContent(child)
child.layout(0, 0, child.measuredWidth, child.measuredHeight)
if (!setup) {
child.setOnApplyWindowInsetsListener { v, insets ->
@ -112,9 +103,9 @@ class BottomSheetContentBehavior<V : View>(context: Context, attributeSet: Attri
}
val bars = insets.systemBarInsetsCompat
val newBottom = max(bars.bottom, consumed)
insets.replaceSystemBarInsetsCompat(
bars.left, bars.top, bars.right, (bars.bottom - consumed).coerceAtLeast(0))
insets.replaceSystemBarInsetsCompat(bars.left, bars.top, bars.right, newBottom)
}
setup = true
@ -123,20 +114,6 @@ class BottomSheetContentBehavior<V : View>(context: Context, attributeSet: Attri
return true
}
private fun measureContent(parent: View, child: View, consumed: Int) {
val contentWidthSpec =
View.MeasureSpec.makeMeasureSpec(parent.measuredWidth, View.MeasureSpec.EXACTLY)
val contentHeightSpec =
View.MeasureSpec.makeMeasureSpec(
parent.measuredHeight - consumed, View.MeasureSpec.EXACTLY)
child.measure(contentWidthSpec, contentHeightSpec)
}
private fun layoutContent(child: View) {
child.layout(0, 0, child.measuredWidth, child.measuredHeight)
}
private fun NeoBottomSheetBehavior<*>.calculateConsumedByBar(): Int {
val offset = calculateSlideOffset()
if (offset == Float.MIN_VALUE || peekHeight < 0) {

View file

@ -27,7 +27,11 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.util.systemBarInsetsCompat
/** A [RecyclerView] that automatically applies insets to itself. */
/**
* A [RecyclerView] that automatically applies insets to itself.
*
* TODO: Correctly handle edge-to-edge regarding scroll effects and saved scroll positions.
*/
open class AuxioRecyclerView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :