Skip to content

Commit

Permalink
Adjust parent alignment calculations for incomplete layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensousa committed Dec 23, 2023
1 parent 57292e0 commit 6bd138e
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import kotlin.math.sign

internal class LayoutAlignment(
private val layoutManager: LayoutManager,
private val layoutInfo: LayoutInfo
private val layoutInfo: LayoutInfo,
) {

companion object {
Expand Down Expand Up @@ -242,40 +242,41 @@ internal class LayoutAlignment(
startViewAnchor = Int.MIN_VALUE
}
if (!reverseLayout) {
parentAlignmentCalculator.updateScrollLimits(
startEdge = startEdge,
endEdge = endEdge,
startViewAnchor = startViewAnchor,
endViewAnchor = endViewAnchor,
alignment = parentAlignment
)
if (layoutInfo.isLoopingAllowed) {
// If we're looping, there's no end scroll limit
parentAlignmentCalculator.invalidateEndLimit()
} else {
parentAlignmentCalculator.updateEndLimit(endEdge, endViewAnchor, parentAlignment)
}
if (layoutInfo.isLoopingStart) {
parentAlignmentCalculator.invalidateStartLimit()
} else {
parentAlignmentCalculator.updateStartLimit(
startEdge, startViewAnchor, parentAlignment
)
}
} else {
parentAlignmentCalculator.updateScrollLimits(
startEdge = endEdge,
endEdge = startEdge,
startViewAnchor = endViewAnchor,
endViewAnchor = startViewAnchor,
alignment = parentAlignment
)
if (layoutInfo.isLoopingAllowed) {
parentAlignmentCalculator.invalidateStartLimit()
} else {
parentAlignmentCalculator.updateStartLimit(endEdge, endViewAnchor, parentAlignment)
}
if (layoutInfo.isLoopingStart) {
parentAlignmentCalculator.invalidateEndLimit()
} else {
parentAlignmentCalculator.updateEndLimit(
startEdge, startViewAnchor, parentAlignment
)
}

}
}

private fun isEndAvailable(
adapterPosition: Int,
maxLayoutPosition: Int,
minLayoutPosition: Int
minLayoutPosition: Int,
): Boolean {
return if (!reverseLayout) {
adapterPosition == maxLayoutPosition
Expand All @@ -287,7 +288,7 @@ internal class LayoutAlignment(
private fun isStartAvailable(
adapterPosition: Int,
maxLayoutPosition: Int,
minLayoutPosition: Int
minLayoutPosition: Int,
): Boolean {
return if (!reverseLayout) {
adapterPosition == minLayoutPosition
Expand Down Expand Up @@ -343,7 +344,7 @@ internal class LayoutAlignment(
private fun calculateAdjustedAlignedScrollDistance(
offset: Int,
view: View,
childView: View
childView: View,
): Int {
var scrollValue = offset
val subPosition = getSubPositionOfView(view, childView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,58 +82,60 @@ internal class ParentAlignmentCalculator {
endScrollLimit = Int.MAX_VALUE
}

fun updateStartLimit(
edge: Int,
viewAnchor: Int,
fun updateScrollLimits(
startEdge: Int,
endEdge: Int,
startViewAnchor: Int,
endViewAnchor: Int,
alignment: ParentAlignment,
) {
startEdge = edge
if (isStartUnknown) {
startScrollLimit = Int.MIN_VALUE
return
this.startEdge = startEdge
this.endEdge = endEdge
val keyline = calculateKeyline(alignment)
startScrollLimit = when {
isStartUnknown -> Int.MIN_VALUE
shouldAlignViewToStart(startViewAnchor, keyline, alignment) -> {
calculateScrollOffsetToStartEdge(startEdge)
}

shouldAlignStartToKeyline(alignment) -> {
calculateScrollOffsetToKeyline(startViewAnchor, keyline)
}

else -> 0
}
val keyLine = calculateKeyline(alignment)
startScrollLimit = if (shouldAlignViewToStart(viewAnchor, keyLine, alignment)) {
calculateScrollOffsetToStartEdge(edge)
} else if (isLayoutComplete()
|| alignment.preferKeylineOverEdge
|| !shouldAlignToStartEdge(alignment.edge)
) {
calculateScrollOffsetToKeyline(viewAnchor, keyLine)
} else {
0
endScrollLimit = when {
isEndUnknown -> Int.MAX_VALUE
shouldAlignViewToEnd(endViewAnchor, keyline, alignment) -> {
calculateScrollOffsetToEndEdge(endEdge)
}

shouldAlignEndToKeyline(alignment) -> {
calculateScrollOffsetToKeyline(endViewAnchor, keyline)
}

else -> 0
}
}

fun updateEndLimit(
edge: Int,
viewAnchor: Int,
alignment: ParentAlignment,
) {
endEdge = edge
if (isEndUnknown) {
endScrollLimit = Int.MAX_VALUE
return
}
val keyline = calculateKeyline(alignment)
endScrollLimit = if (shouldAlignViewToEnd(viewAnchor, keyline, alignment)) {
calculateScrollOffsetToEndEdge(edge)
} else if (isLayoutComplete()
|| alignment.preferKeylineOverEdge
|| !shouldAlignToEndEdge(alignment.edge)
) {
calculateScrollOffsetToKeyline(viewAnchor, keyline)
} else {
0
}
private fun shouldAlignStartToKeyline(alignment: ParentAlignment): Boolean {
return isLayoutComplete()
|| alignment.preferKeylineOverEdge
|| !shouldAlignToStartEdge(alignment.edge)
}

private fun shouldAlignEndToKeyline(alignment: ParentAlignment): Boolean {
return isLayoutComplete()
|| alignment.preferKeylineOverEdge
|| !shouldAlignToEndEdge(alignment.edge)
}

private fun calculateScrollOffsetToEndEdge(edge: Int): Int {
return edge - getLayoutEndEdge()
return edge - getLayoutAbsoluteEnd()
}

private fun calculateScrollOffsetToStartEdge(edge: Int): Int {
return edge - getLayoutStartEdge()
return edge - getLayoutAbsoluteStart()
}

/**
Expand Down Expand Up @@ -192,8 +194,8 @@ internal class ParentAlignmentCalculator {
if (isStartUnknown || !shouldAlignToStartEdge(alignment.edge)) {
return false
}
if (isLayoutComplete()) {
return viewAnchor + getLayoutStartEdge() <= startEdge + keyline
if (isLayoutComplete() || isLayoutCompleteInOppositeDirection()) {
return viewAnchor + getLayoutAbsoluteStart() <= startEdge + keyline
}
return isLayoutIncomplete() && !alignment.preferKeylineOverEdge
}
Expand All @@ -206,8 +208,8 @@ internal class ParentAlignmentCalculator {
if (isEndUnknown || !shouldAlignToEndEdge(alignment.edge)) {
return false
}
if (isLayoutComplete()) {
return viewAnchor + getLayoutEndEdge() >= endEdge + keyline
if (isLayoutComplete() || isLayoutCompleteInOppositeDirection()) {
return viewAnchor + getLayoutAbsoluteEnd() >= endEdge + keyline
}
return isLayoutIncomplete() && !alignment.preferKeylineOverEdge
}
Expand All @@ -216,26 +218,34 @@ internal class ParentAlignmentCalculator {
return anchor - keyline
}

private fun getLayoutEndEdge(): Int {
private fun getLayoutAbsoluteEnd(): Int {
return size - paddingEnd
}

private fun getLayoutStartEdge(): Int {
private fun getLayoutAbsoluteStart(): Int {
return paddingStart
}

private fun isLayoutComplete(): Boolean {
return endEdge >= getLayoutEndEdge() && startEdge <= getLayoutStartEdge()
return endEdge >= getLayoutAbsoluteEnd() && startEdge <= getLayoutAbsoluteStart()
}

private fun isLayoutCompleteInOppositeDirection(): Boolean {
return if (!reverseLayout) {
startEdge <= getLayoutAbsoluteStart()
} else {
endEdge >= getLayoutAbsoluteEnd()
}
}

private fun isLayoutIncomplete(): Boolean {
if (isEndUnknown || isStartUnknown) {
return false
}
return if (!reverseLayout) {
endEdge < getLayoutEndEdge()
endEdge < getLayoutAbsoluteEnd()
} else {
startEdge > getLayoutStartEdge()
startEdge > getLayoutAbsoluteStart()
}
}

Expand Down
Loading

0 comments on commit 6bd138e

Please sign in to comment.