How to implement custom LayoutManager

How to implement custom LayoutManager

5f533179da1c82722252cbcb93e7356f?s=128

Moyuru Aizawa

March 08, 2019
Tweet

Transcript

  1. -BZPVU.BOBHFSͷ࣮૷ํ๏ @MoyuruAizawa

  2. MoyuruAizawa Moyuru Aizawa
 Software engineer of CATS Div. CyberAgent Inc.

    
 Previously at Pairs Div. Eureka Inc.
  3. .PZVSV"J[BXB5JNFUBCMF-BZPVU http://bit.ly/ttlayout

  4. ‣ -BZPVU.BOBHFSͷ֓ཁ ‣ ؆қ-JOFBS-BZPVU.BOBHFSΛྫʹ࣮૷ํ๏ ࠓ೔࿩͢͜ͱ

  5. ‣ 3FDZDMFS7JFXͷDIJMEWJFXTͷϨΠΞ΢τΛ୲౰͢ΔϞδϡʔϧ ‣ -BZPVU.BOBHFSΛม͑Δ͜ͱͰ༷ʑͳϨΠΞ΢τΛ࣮ݱ͢Δࣄ͕Ͱ͖ Δ -BZPVU.BOBHFSͷ֓ཁ

  6. ‣ ؔ਺ػೳ͕ଟ͍ͷͰ͔ͳΓେม ‣ ϨΠΞ΢τͷෳࡶ͞Λ૿͢ཁૉ ‣ 0SJFOUBUJPO 7FSUJDBM-BZPVU)PSJ[POUBM-BZPVU  ‣ 3FWFSTF-BZPVU

    ‣ -5335- -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. ‣ 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ͷؔ਺ػೳ
  9. ‣ 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ͷؔ਺ػೳ
  10. ‣ 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ͷؔ਺ػೳ
  11. ‣ 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ͷؔ਺ػೳ
  12. ‣ 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ͷؔ਺ػೳ
  13. ‣ 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ͷؔ਺ػೳ
  14. ‣ ϨΠΞ΢τͷॳظԽ ‣ BEBQUFSDIBOHF ‣ SFRVFTU-BZPVU ‣ ্͔Βॱ൪ʹϨΠΞ΢τ͍ͯ͘͠ 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 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. override fun onLayoutCompleted(state: State?) { savedState = null } PO-BZPVU$PNQMFUFE

  36. ‣ DIJMEWJFXTͷεϥΠυ ‣ ը໘͔Βग़ͨDIJMEWJFXTͷSFNPWF ‣ ۭ͖εϖʔεʹDIJMEWJFXTͷBEE TDSPMM7FSUJDBMMZ#Z

  37. ‣ DIJMEWJFXTͷεϥΠυ ‣ ը໘͔Βग़ͨDIJMEWJFXTͷSFNPWF ‣ ۭ͖εϖʔεʹDIJMEWJFXTͷBEE TDSPMM7FSUJDBMMZ#Z

  38. ‣ DIJMEWJFXTͷεϥΠυ ‣ ը໘͔Βग़ͨDIJMEWJFXTͷSFNPWF ‣ ۭ͖εϖʔεʹDIJMEWJFXTͷBEE TDSPMM7FSUJDBMMZ#Z

  39. ‣ DIJMEWJFXTͷεϥΠυ ‣ ը໘͔Βग़ͨDIJMEWJFXTͷSFNPWF ‣ ۭ͖εϖʔεʹDIJMEWJFXTͷBEE TDSPMM7FSUJDBMMZ#Z

  40. 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
  41. 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
  42. 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
  43. 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
  44. private fun recycleTop(recycler: Recycler) { children.forEach { if (getDecoratedBottom(it) <

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

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

    parentTop) removeAndRecycleView(it, recycler) else return } } TDSPMM7FSUJDBMMZ#Z
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. ‣ ࢦఆϙδγϣϯͰMBZPVU͠௚͢ TDSPMM5P1PTJUJPO

  54. override fun scrollToPosition(position: Int) { pendingScrollPosition = position requestLayout() }

    TDSPMM5P1PTJUJPO
  55. 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
  56. 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
  57. 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
  58. 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
  59. 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
  60. ͻͨ͢ΒੵΈ໦Λ͍ͯ͘͠࡞ۀ Ͱ͢

  61. 5IBOLZPV