Slide 1

Slide 1 text

-BZPVU.BOBHFSͷ࣮૷ํ๏ @MoyuruAizawa

Slide 2

Slide 2 text

MoyuruAizawa Moyuru Aizawa
 Software engineer of CATS Div. CyberAgent Inc. 
 Previously at Pairs Div. Eureka Inc.

Slide 3

Slide 3 text

.PZVSV"J[BXB5JNFUBCMF-BZPVU http://bit.ly/ttlayout

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

‣ 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ͷؔ਺ػೳ

Slide 8

Slide 8 text

‣ 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ͷؔ਺ػೳ

Slide 9

Slide 9 text

‣ 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ͷؔ਺ػೳ

Slide 10

Slide 10 text

‣ 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ͷؔ਺ػೳ

Slide 11

Slide 11 text

‣ 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ͷؔ਺ػೳ

Slide 12

Slide 12 text

‣ 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ͷؔ਺ػೳ

Slide 13

Slide 13 text

‣ 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ͷؔ਺ػೳ

Slide 14

Slide 14 text

‣ ϨΠΞ΢τͷॳظԽ ‣ BEBQUFSDIBOHF ‣ SFRVFTU-BZPVU ‣ ্͔Βॱ൪ʹϨΠΞ΢τ͍ͯ͘͠ PO-BZPVU$IJMESFO

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

override fun onLayoutCompleted(state: State?) { savedState = null } PO-BZPVU$PNQMFUFE

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

‣ ࢦఆϙδγϣϯͰMBZPVU͠௚͢ TDSPMM5P1PTJUJPO

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

ͻͨ͢ΒੵΈ໦Λ͍ͯ͘͠࡞ۀ Ͱ͢

Slide 61

Slide 61 text

5IBOLZPV