Skip to content

Commit

Permalink
Merge pull request #176 from rubensousa/fix_auto_alignment
Browse files Browse the repository at this point in the history
Restore to previous layout anchor if user scrolls via touch
  • Loading branch information
rubensousa committed Dec 27, 2023
2 parents 2c76fd3 + 36a348a commit e925781
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 10 deletions.
9 changes: 9 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Version 1.2.0

### 1.2.0-alpha02

2023-12-27

#### Bug fixes

- Fixed layout jumping to the top when the user scrolls with touch events ([#171](https://github.com/rubensousa/DpadRecyclerView/issues/171))
- Fixed alignment configuration not being respected for small lists ([#172](https://github.com/rubensousa/DpadRecyclerView/issues/172))

### 1.2.0-alpha01

2023-11-25
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ open class DpadRecyclerView @JvmOverloads constructor(

final override fun onRtlPropertiesChanged(layoutDirection: Int) {
super.onRtlPropertiesChanged(layoutDirection)
pivotLayoutManager?.onRtlPropertiesChanged()
pivotLayoutManager?.onRtlPropertiesChanged(layoutDirection)
}

final override fun smoothScrollBy(dx: Int, dy: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ internal class LayoutConfiguration(properties: Properties) {
var recycleChildrenOnDetach: Boolean = false
private set

var keepLayoutAnchor: Boolean = false
private set

init {
setSpanCount(properties.spanCount)
setOrientation(properties.orientation)
Expand Down Expand Up @@ -250,4 +253,10 @@ internal class LayoutConfiguration(properties: Properties) {
}
}

// This flag will be used to try to keep layout consistency
// whenever the user scrolls the layout using touch events
fun setKeepLayoutAnchor(keep: Boolean) {
keepLayoutAnchor = keep
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import com.rubensousa.dpadrecyclerview.layoutmanager.scroll.LayoutScroller
*/
class PivotLayoutManager(properties: Properties) : RecyclerView.LayoutManager() {

private var layoutDirection: Int = View.LAYOUT_DIRECTION_LTR
private val configuration = LayoutConfiguration(properties)
private val layoutInfo = LayoutInfo(this, configuration)
private val pivotSelector = PivotSelector(this, layoutInfo)
Expand Down Expand Up @@ -389,7 +390,11 @@ class PivotLayoutManager(properties: Properties) : RecyclerView.LayoutManager()
pivotLayout.onRestoreInstanceState(state)
}

internal fun onRtlPropertiesChanged() {
internal fun onRtlPropertiesChanged(layoutDirection: Int) {
if (this.layoutDirection == layoutDirection) {
return
}
this.layoutDirection = layoutDirection
requestLayout()
}

Expand All @@ -406,6 +411,7 @@ class PivotLayoutManager(properties: Properties) : RecyclerView.LayoutManager()
internal fun getConfig() = configuration

internal fun setScrollingFromTouchEvent(isTouching: Boolean) {
configuration.setKeepLayoutAnchor(isTouching)
isScrollingFromTouchEvent = isTouching
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ internal class FocusDispatcher(
* Request focus to the current pivot if it exists
*/
fun onRequestFocusInDescendants(direction: Int, previouslyFocusedRect: Rect?): Boolean {
if (configuration.isFocusSearchDisabled) return false
val view = layout.findViewByPosition(pivotSelector.position) ?: return false
return view.requestFocus(direction, previouslyFocusedRect)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal class PivotLayout(
private val configuration: LayoutConfiguration,
private val pivotSelector: PivotSelector,
private val scroller: LayoutScroller,
private val layoutInfo: LayoutInfo
private val layoutInfo: LayoutInfo,
) {

companion object {
Expand All @@ -50,6 +50,7 @@ internal class PivotLayout(
private var structureEngineer = createStructureEngineer()
private val layoutCompleteListeners = ArrayList<DpadRecyclerView.OnLayoutCompletedListener>()
private val itemChanges = ItemChanges()
private var anchor: Int? = null

fun updateStructure() {
structureEngineer = createStructureEngineer()
Expand Down Expand Up @@ -91,7 +92,7 @@ internal class PivotLayout(
private fun preLayoutChildren(
pivotPosition: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
state: RecyclerView.State,
) {
val childCount = layoutManager.childCount
if (childCount == 0) {
Expand All @@ -116,8 +117,16 @@ internal class PivotLayout(
structureEngineer.logChildren()
}

if (configuration.keepLayoutAnchor) {
saveAnchorState()
}

structureEngineer.layoutChildren(pivotSelector.position, itemChanges, recycler, state)

if (configuration.keepLayoutAnchor) {
restoreAnchorState(recycler, state)
}

if (DpadRecyclerView.DEBUG) {
Log.i(TAG, "LayoutFinished")
structureEngineer.logChildren()
Expand All @@ -126,6 +135,41 @@ internal class PivotLayout(
structureEngineer.onLayoutFinished()
}

private fun saveAnchorState() {
val currentPivotPosition = if (!layoutInfo.shouldReverseLayout()) {
layoutInfo.findFirstVisiblePosition()
} else {
layoutInfo.findLastVisiblePosition()
}
if (currentPivotPosition == RecyclerView.NO_POSITION) {
return
}
pivotSelector.update(currentPivotPosition)
layoutInfo.findViewByPosition(currentPivotPosition)?.let { view ->
anchor = if (!layoutInfo.shouldReverseLayout()) {
layoutInfo.getDecoratedStart(view)
} else {
layoutInfo.getDecoratedEnd(view)
}
}
}

private fun restoreAnchorState(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
anchor?.let { previousAnchor ->
if (pivotSelector.position != RecyclerView.NO_POSITION) {
layoutInfo.findViewByPosition(pivotSelector.position)?.let { view ->
val currentAnchor = if (!layoutInfo.shouldReverseLayout()) {
layoutInfo.getDecoratedStart(view)
} else {
layoutInfo.getDecoratedEnd(view)
}
scrollBy(currentAnchor - previousAnchor, recycler, state)
}
}
anchor = null
}
}

fun reset() {
structureEngineer.clear()
}
Expand Down Expand Up @@ -173,7 +217,7 @@ internal class PivotLayout(
fun scrollHorizontallyBy(
dx: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
state: RecyclerView.State,
): Int {
if (configuration.isVertical()) {
return 0
Expand All @@ -184,7 +228,7 @@ internal class PivotLayout(
fun scrollVerticallyBy(
dy: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
state: RecyclerView.State,
): Int {
if (configuration.isHorizontal()) {
return 0
Expand Down Expand Up @@ -216,7 +260,7 @@ internal class PivotLayout(
private fun scrollBy(
offset: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
state: RecyclerView.State,
): Int {
// Do nothing if we don't have children
if (state.itemCount == 0 || offset == 0 || !configuration.isLayoutEnabled) {
Expand All @@ -242,7 +286,7 @@ internal class PivotLayout(
val selectedPosition: Int,
val isLoopingStart: Boolean,
val isLoopingAllowed: Boolean,
val loopDirection: DpadLoopDirection
val loopDirection: DpadLoopDirection,
) : Parcelable {

companion object CREATOR : Parcelable.Creator<SavedState> {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ kotlin.code.style=official
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.enableR8.fullMode=true
LIBRARY_VERSION=1.2.0-alpha01
LIBRARY_VERSION=1.2.0-alpha02
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ theme:

extra:
dpadrecyclerview:
version: '1.2.0-alpha01'
version: '1.2.0-alpha02'
social:
- icon: 'fontawesome/brands/github'
link: 'https://github.com/rubensousa/DpadRecyclerView'
Expand Down

0 comments on commit e925781

Please sign in to comment.