Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to implement custom LayoutManager

How to implement custom LayoutManager

Moyuru Aizawa

March 08, 2019
Tweet

More Decks by Moyuru Aizawa

Other Decks in Programming

Transcript

  1. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  2. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  3. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  4. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  5. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  6. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  7. ‣ PO-BZPVU$IJMESFO ‣ TDSPMM7FSUJDBMMZ#ZTDSPMM)PSJ[POUBMMZ#Z ‣ TDSPMM5P ‣ TNPPUI4DSPMM5P ‣ DPNQVUF7FSUJDBM4DSPMM&YUFOUDPNQVUF)PSJ[POUBM4DSPMM&YUFOU

    ‣ DPNQVUF7FSUJDBM4DSPMM0GGTFUDPNQVUF)PSJ[POUBM4DSPMM0GGTFU ‣ DPNQVUF7FSUJDBM4DSPMM3BOHFDPNQVUF)PSJ[POUBM4DSPMM3BOHF ‣ *UFN1SFGFUDI ‣ *UFN%FDPSBUJPOT ‣ *UFN"OJNBUPST ‣ 1SFEJDUJWF"OJNBUJPOT ‣ ʜ -BZPVU.BOBHFSͷؔ਺ػೳ
  8. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  9. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  10. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  11. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  12. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  13. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  14. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  15. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  16. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  17. private fun addRow(position: Int, offsetY: Int, isAppend: Boolean, recycler: Recycler):

    Int { val view = recycler.getViewForPosition(position) addView(view, if (isAppend) -1 else 0) measureChildWithMargins(view, 0, 0) val height = getDecoratedMeasuredHeight(view) val width = getDecoratedMeasuredWidth(view) val top = if (isAppend) offsetY else offsetY - height val bottom = top + height layoutDecoratedWithMargins( view, parentLeft, top, parentLeft + width, bottom) return height } PO-BZPVU$IJMESFO
  18. private fun fillChunk(startPosition: Int, startY: Int, isAppend: Boolean, recycler: Recycler)

    { val remainingSpace = if (isAppend) parentBottom - startY else startY - parentTop var offsetY = startY val range = if (isAppend) startPosition until itemCount else startPosition downTo 0 for (position in range) { val height = addRow(position, offsetY, isAppend, recycler) offsetY += if (isAppend) height else -height val consumed = abs(offsetY - startY) if (consumed > remainingSpace) break } } PO-BZPVU$IJMESFO
  19. private fun fillChunk(startPosition: Int, startY: Int, isAppend: Boolean, recycler: Recycler)

    { val remainingSpace = if (isAppend) parentBottom - startY else startY - parentTop var offsetY = startY val range = if (isAppend) startPosition until itemCount else startPosition downTo 0 for (position in range) { val height = addRow(position, offsetY, isAppend, recycler) offsetY += if (isAppend) height else -height val consumed = abs(offsetY - startY) if (consumed > remainingSpace) break } } PO-BZPVU$IJMESFO
  20. private fun fillChunk(startPosition: Int, startY: Int, isAppend: Boolean, recycler: Recycler)

    { val remainingSpace = if (isAppend) parentBottom - startY else startY - parentTop var offsetY = startY val range = if (isAppend) startPosition until itemCount else startPosition downTo 0 for (position in range) { val height = addRow(position, offsetY, isAppend, recycler) offsetY += if (isAppend) height else -height val consumed = abs(offsetY - startY) if (consumed > remainingSpace) break } } PO-BZPVU$IJMESFO
  21. private fun fillChunk(startPosition: Int, startY: Int, isAppend: Boolean, recycler: Recycler)

    { val remainingSpace = if (isAppend) parentBottom - startY else startY - parentTop var offsetY = startY val range = if (isAppend) startPosition until itemCount else startPosition downTo 0 for (position in range) { val height = addRow(position, offsetY, isAppend, recycler) offsetY += if (isAppend) height else -height val consumed = abs(offsetY - startY) if (consumed > remainingSpace) break } } PO-BZPVU$IJMESFO
  22. override fun onLayoutChildren(recycler: Recycler, state: State) { if (itemCount ==

    0) { detachAndScrapAttachedViews(recycler) return } val restoredFirstVisibleView = getChildAt(0) val restoredPosition = restoredFirstVisibleView?.adapterPosition val restoredTop = restoredFirstVisibleView?.let(this::getDecoratedTop) if (childCount > 0) detachAndScrapAttachedViews(recycler) fillChunk(restoredPosition ?: 0, restoredTop ?: parentTop, isAppend = true, recycler = recycler) } PO-BZPVU$IJMESFO
  23. override fun onLayoutChildren(recycler: Recycler, state: State) { if (itemCount ==

    0) { detachAndScrapAttachedViews(recycler) return } val restoredFirstVisibleView = getChildAt(0) val restoredPosition = restoredFirstVisibleView?.adapterPosition val restoredTop = restoredFirstVisibleView?.let(this::getDecoratedTop) if (childCount > 0) detachAndScrapAttachedViews(recycler) fillChunk(restoredPosition ?: 0, restoredTop ?: parentTop, isAppend = true, recycler = recycler) } PO-BZPVU$IJMESFO
  24. override fun onLayoutChildren(recycler: Recycler, state: State) { if (itemCount ==

    0) { detachAndScrapAttachedViews(recycler) return } val restoredFirstVisibleView = getChildAt(0) val restoredPosition = restoredFirstVisibleView?.adapterPosition val restoredTop = restoredFirstVisibleView?.let(this::getDecoratedTop) if (childCount > 0) detachAndScrapAttachedViews(recycler) fillChunk(restoredPosition ?: 0, restoredTop ?: parentTop, isAppend = true, recycler = recycler) } PO-BZPVU$IJMESFO
  25. override fun onLayoutChildren(recycler: Recycler, state: State) { if (itemCount ==

    0) { detachAndScrapAttachedViews(recycler) return } val restoredFirstVisibleView = getChildAt(0) val restoredPosition = restoredFirstVisibleView?.adapterPosition val restoredTop = restoredFirstVisibleView?.let(this::getDecoratedTop) if (childCount > 0) detachAndScrapAttachedViews(recycler) fillChunk(restoredPosition ?: 0, restoredTop ?: parentTop, isAppend = true, recycler = recycler) } PO-BZPVU$IJMESFO
  26. override fun onSaveInstanceState(): Parcelable? { val firstVisibleItem = getChildAt(0) ?:

    return null return SavedState(firstVisibleItem.adapterPosition, getDecoratedTop(firstVisibleItem)) } override fun onRestoreInstanceState(state: Parcelable?) { savedState = state as? SavedState } PO-BZPVU$IJMESFO
  27. val restoredFirstVisibleView = getChildAt(0) val restoredPosition = savedState?.firstVisibleItemPosition ?: restoredFirstVisibleView?.adapterPosition

    val restoredTop = savedState?.firstVisibleItemTop ?: restoredFirstVisibleView?.let(this::getDecoratedTop) if (childCount > 0) detachAndScrapAttachedViews(recycler) if (restoredPosition != null && restoredTop != null && restoredPosition < itemCount) fillChunk(restoredPosition, restoredTop, isAppend = true, recycler = recycler) else fillChunk(0, parentTop, isAppend = true, recycler = recycler) PO-BZPVU$IJMESFO
  28. private fun calculateActualDy(dy: Int): Int { if (dy == 0)

    return 0 return if (dy > 0) { // up swipe val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (lastView.adapterPosition == itemCount - 1) if (bottom == parentBottom) 0 else min(bottom - parentBottom, dy) else dy } else { val firstView = getChildAt(0) ?: return 0 val top = getDecoratedTop(firstView) if (firstView.adapterPosition == 0) if (top == parentTop) 0 else max(top - parentTop, dy) else dy } } TDSPMM7FSUJDBMMZ#Z
  29. private fun calculateActualDy(dy: Int): Int { if (dy == 0)

    return 0 return if (dy > 0) { // up swipe val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (lastView.adapterPosition == itemCount - 1) if (bottom == parentBottom) 0 else min(bottom - parentBottom, dy) else dy } else { val firstView = getChildAt(0) ?: return 0 val top = getDecoratedTop(firstView) if (firstView.adapterPosition == 0) if (top == parentTop) 0 else max(top - parentTop, dy) else dy } } TDSPMM7FSUJDBMMZ#Z
  30. private fun calculateActualDy(dy: Int): Int { if (dy == 0)

    return 0 return if (dy > 0) { // up swipe val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (lastView.adapterPosition == itemCount - 1) if (bottom == parentBottom) 0 else min(bottom - parentBottom, dy) else dy } else { val firstView = getChildAt(0) ?: return 0 val top = getDecoratedTop(firstView) if (firstView.adapterPosition == 0) if (top == parentTop) 0 else max(top - parentTop, dy) else dy } } TDSPMM7FSUJDBMMZ#Z
  31. private fun calculateActualDy(dy: Int): Int { if (dy == 0)

    return 0 return if (dy > 0) { // up swipe val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (lastView.adapterPosition == itemCount - 1) if (bottom == parentBottom) 0 else min(bottom - parentBottom, dy) else dy } else { val firstView = getChildAt(0) ?: return 0 val top = getDecoratedTop(firstView) if (firstView.adapterPosition == 0) if (top == parentTop) 0 else max(top - parentTop, dy) else dy } } TDSPMM7FSUJDBMMZ#Z
  32. private fun recycleTop(recycler: Recycler) { children.forEach { if (getDecoratedBottom(it) <

    parentTop) removeAndRecycleView(it, recycler) else return } } TDSPMM7FSUJDBMMZ#Z
  33. private fun recycleTop(recycler: Recycler) { children.forEach { if (getDecoratedBottom(it) <

    parentTop) removeAndRecycleView(it, recycler) else return } } TDSPMM7FSUJDBMMZ#Z
  34. private fun recycleTop(recycler: Recycler) { children.forEach { if (getDecoratedBottom(it) <

    parentTop) removeAndRecycleView(it, recycler) else return } } TDSPMM7FSUJDBMMZ#Z
  35. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  36. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  37. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  38. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  39. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  40. override fun scrollVerticallyBy(dy: Int, recycler: Recycler, state: State): Int {

    val actualDy = calculateActualDy(dy) if (actualDy == 0) return 0 offsetChildrenVertical(-actualDy) if (actualDy > 0) { recycleTop(recycler) val lastView = getChildAt(childCount - 1) ?: return 0 val bottom = getDecoratedBottom(lastView) if (bottom < parentBottom) fillChunk(lastView.adapterPosition + 1, bottom, true, recycler) } else { … } return actualDy } TDSPMM7FSUJDBMMZ#Z
  41. override fun onLayoutChildren(recycler: Recycler, state: State) { … if (pendingScrollPosition

    != RecyclerView.NO_POSITION) { fillChunk(pendingScrollPosition, parentTop, true, recycler) val lastVisibleView = getChildAt(childCount - 1) ?: return val bottom = getDecoratedBottom(lastVisibleView) if (lastVisibleView.adapterPosition.isLast && bottom < parentBottom) fixLayoutGap() return } … } TDSPMM5P1PTJUJPO
  42. override fun onLayoutChildren(recycler: Recycler, state: State) { … if (pendingScrollPosition

    != RecyclerView.NO_POSITION) { fillChunk(pendingScrollPosition, parentTop, true, recycler) val lastVisibleView = getChildAt(childCount - 1) ?: return val bottom = getDecoratedBottom(lastVisibleView) if (lastVisibleView.adapterPosition.isLast && bottom < parentBottom) fixLayoutGap() return } … } TDSPMM5P1PTJUJPO
  43. override fun onLayoutChildren(recycler: Recycler, state: State) { … if (pendingScrollPosition

    != RecyclerView.NO_POSITION) { fillChunk(pendingScrollPosition, parentTop, true, recycler) val lastVisibleView = getChildAt(childCount - 1) ?: return val bottom = getDecoratedBottom(lastVisibleView) if (lastVisibleView.adapterPosition.isLast && bottom < parentBottom) fixLayoutGap() return } … } TDSPMM5P1PTJUJPO 99
  44. override fun onLayoutChildren(recycler: Recycler, state: State) { … if (pendingScrollPosition

    != RecyclerView.NO_POSITION) { fillChunk(pendingScrollPosition, parentTop, true, recycler) val lastVisibleView = getChildAt(childCount - 1) ?: return val bottom = getDecoratedBottom(lastVisibleView) if (lastVisibleView.adapterPosition.isLast && bottom < parentBottom) fixLayoutGap() return } … } TDSPMM5P1PTJUJPO 99
  45. override fun onLayoutChildren(recycler: Recycler, state: State) { … if (pendingScrollPosition

    != RecyclerView.NO_POSITION) { fillChunk(pendingScrollPosition, parentTop, true, recycler) val lastVisibleView = getChildAt(childCount - 1) ?: return val bottom = getDecoratedBottom(lastVisibleView) if (lastVisibleView.adapterPosition.isLast && bottom < parentBottom) fixLayoutGap() return } … } TDSPMM5P1PTJUJPO 99 98 97 96 95