Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Deep Dive Into LayoutManager for RecyclerView

Highly recommend look at the mp4 video (https://drive.google.com/open?id=1_k0jlSilVkekIgqU6NHAcx01pjT8cee5) or the recorded talk (not available yet)

DroidKaigi 2018 2018/2/8 Room3

Related Books

Free with a 30 day trial from Scribd

See all
  • Be the first to comment

Deep Dive Into LayoutManager for RecyclerView

  1. 1. thagikura Deep Dive Into LayoutManager 
 for RecyclerView
  2. 2. $ whoami Takeshi Hagikura @thagikura 
 Developer Relations
 @Google
  3. 3. RecyclerView
  4. 4. RecyclerView Adapter Recycler LayoutManager ItemDecoration ItemAnimator RecycledViewPool TouchHelper DiffUtil
 

  5. 5. LinearLayoutManager
  6. 6. GridLayoutManager
  7. 7. StaggeredGridLayoutManager
  8. 8. Is it possible to add a custom LayoutManager?
  9. 9. FlexboxLayoutManager
  10. 10. github.com/google/flexbox-layout
  11. 11. Ports Flexbox in CSS to Android
  12. 12. How to create a custom LayoutManager?
  13. 13. Think before you build it Much harder than custom view Gives you much flexibility on top of RecyclerView features
  14. 14. At the bare minimum, need to override…
  15. 15. onLayoutChildren Called on: - initial layout - adapter changes Lay out all relevant child views
  16. 16. If this isViewGroup (except RecyclerView) All child views on memory
  17. 17. In RecyclerView + LayoutManager Only visible views should be on memory
  18. 18. onLayoutChildren 1. Find the anchor position
  19. 19. Anchor position Starting position to put views. Start with 0 on initial layout.
 
 Remember the first visible view to restore the state
  20. 20. onLayoutChildren 1. Find the anchor position 2. Calculate how many items
 should be in visible portion
  21. 21. onLayoutChildren 1. Find the anchor position 2. Calculate how many items
 should be in visible portion 3. Fill toward end
  22. 22. private int fill(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState) { int start = layoutState.mAvailable; int remainingSpace = layoutState.mAvailable; int consumed = 0; while (remainingSpace > 0 && layoutState.hasMore(state, mFlexLines)) { FlexLine flexLine = mFlexLines.get(layoutState.mFlexLinePosition); layoutState.mPosition = flexLine.mFirstIndex; consumed += layoutFlexLine(flexLine, layoutState); remainingSpace -= flexLine.getCrossSize(); } layoutState.mAvailable -= consumed; return start - layoutState.mAvailable; } Simplified version of fill
  23. 23. private int fill(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState) { int start = layoutState.mAvailable; int remainingSpace = layoutState.mAvailable; int consumed = 0; while (remainingSpace > 0 && layoutState.hasMore(state, mFlexLines)) { FlexLine flexLine = mFlexLines.get(layoutState.mFlexLinePosition); layoutState.mPosition = flexLine.mFirstIndex; consumed += layoutFlexLine(flexLine, layoutState); remainingSpace -= flexLine.getCrossSize(); } layoutState.mAvailable -= consumed; return start - layoutState.mAvailable; } mAvailable: Amount of pixels need to be filled mDirection: START | END
  24. 24. private int fill(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState) { int start = layoutState.mAvailable; int remainingSpace = layoutState.mAvailable; int consumed = 0; while (remainingSpace > 0 && layoutState.hasMore(state, mFlexLines)) { FlexLine flexLine = mFlexLines.get(layoutState.mFlexLinePosition); layoutState.mPosition = flexLine.mFirstIndex; consumed += layoutFlexLine(flexLine, layoutState); remainingSpace -= flexLine.getCrossSize(); } layoutState.mAvailable -= consumed; return start - layoutState.mAvailable; } Put views and loop until mAvailable < 0
  25. 25. onLayoutChildren 1. Find the anchor position 2. Calculate how many items
 should be in visible portion 3. Fill toward end 4. Fill toward start
  26. 26. Why fill toward both directions?
  27. 27. In some cases anchor position may be at the bottom
  28. 28. 1 2 3 4 5 6 7 8 9 10 11 scrollToPosition(50) 42 43 44 45 46 47 48 49 50 Anchor position
  29. 29. scrollVerticallyBy Interact with scroll by the user
  30. 30. @Override public boolean canScrollVertically() { return true; } Could be false depending on attributes. E.g. Orientation in LinearLayoutManager
  31. 31. @Override public int scrollVerticallyBy(int dy, 
 RecyclerView.Recycler recycler, RecyclerView.State state) { if (isMainAxisDirectionHorizontal()) { int scrolled = 
 handleScrollingCrossAxis(dy, recycler, state); mViewCache.clear(); return scrolled; } else { int scrolled = handleScrollingMainAxis(dy); mAnchorInfo.mPerpendicularCoordinate += scrolled; mSubOrientationHelper.offsetChildren(-scrolled); return scrolled; } }
  32. 32. @Override public int scrollVerticallyBy(int dy, 
 RecyclerView.Recycler recycler, RecyclerView.State state) { if (isMainAxisDirectionHorizontal()) { int scrolled = 
 handleScrollingCrossAxis(dy, recycler, state); mViewCache.clear(); return scrolled; } else { int scrolled = handleScrollingMainAxis(dy); mAnchorInfo.mPerpendicularCoordinate += scrolled; mSubOrientationHelper.offsetChildren(-scrolled); return scrolled; } } Distance to scroll in pixels
  33. 33. @Override public int scrollVerticallyBy(int dy, 
 RecyclerView.Recycler recycler, RecyclerView.State state) { if (isMainAxisDirectionHorizontal()) { int scrolled = 
 handleScrollingCrossAxis(dy, recycler, state); mViewCache.clear(); return scrolled; } else { int scrolled = handleScrollingMainAxis(dy); mAnchorInfo.mPerpendicularCoordinate += scrolled; mSubOrientationHelper.offsetChildren(-scrolled); return scrolled; } } The actual distance scrolled
  34. 34. Small dy Only shift existing views mRecyclerView.offsetChildrenVertical(dy);
  35. 35. Large dy
  36. 36. Large dy Recycle views no longer visible
  37. 37. Large dy Fill appearing views
  38. 38. What does Recycle mean?
  39. 39. Two types of cache in RecyclerView 1. Recycle 2. Scrap
  40. 40. Recycler RecycledViewPool 1. Recycle
  41. 41. Recycler RecycledViewPool LayoutManager recycler.recycleView(View) 1. Recycle
  42. 42. Recycler RecycledViewPool LayoutManager recycler.recycleView(View) 1. Recycle Considered as dirty
  43. 43. RecyclerRecycler RecycledViewPool Can be shared across multiple RecyclerViews
  44. 44. Recycler Scrap Heap 2. Scrap
  45. 45. Recycler Scrap Heap LayoutManager recycler.scrapView(View) 2. Scrap
  46. 46. Recycler Scrap Heap LayoutManager detachAndScrapAttachedViews RecyclerView recycler.scrapView(View) 2. Scrap
  47. 47. How to retrieve aView?
  48. 48. LayoutManager Adapter Recycler recycler.getViewForPosition(int)
  49. 49. Case1. Found in scrap Case2. Found in Recycled Pool Case3. Not found in cache
  50. 50. LayoutManager Adapter Recycler Case1. Found in scrap
  51. 51. LayoutManager Adapter Recycler Case2. Found in Recycled Pool adapter.bindViewHolder
  52. 52. LayoutManager Adapter Recycler Case2. Found in Recycled Pool
  53. 53. LayoutManager Adapter Recycler Case3. Not found in cache adapter.createViewHolder
  54. 54. LayoutManager Adapter Recycler Case3. Not found in cache
  55. 55. Use scrap if you re-attach in a same layout pass Use recycle for views no longer needed
  56. 56. scrollHorizontallyBy Same with vertical except for the direction
  57. 57. Now you implement basic functions. Is it enough?
  58. 58. Could be useable... but NO.
  59. 59. scrollTo(position) smoothScrollTo(position) Fast Scrolling Item Decorations Item prefetch Predictive Animations There are a lot more…
  60. 60. scrollTo(position) smoothScrollTo(position) Fast Scrolling Item Decorations Item prefetch Predictive Animations There are a lot more…
  61. 61. Predictive Animations
  62. 62. Off OnAdd aView
  63. 63. Off OnDelete aView
  64. 64. @Override public boolean supportsPredictiveItemAnimations() { return true; }
  65. 65. onLayoutChildren Real Layout Pre-layout
  66. 66. In pre-layout Lay out all the views currently visible and additional views that are appearing (or disappearing) after the animation
  67. 67. Pre-layout Remaining Appearing Disappearing To be inserted at this positionVisible area
  68. 68. Real-layout Remaining Appearing Disappearing Visible area
  69. 69. Pre-layout Remaining Appearing Disappearing To be deletedVisible area
  70. 70. Real layout Remaining Appearing Disappearing Visible area
  71. 71. Now you know the basics of building a custom LayoutManager
  72. 72. Resources Source of default LayoutManagers 
 github.com/google/flexbox-layout 
 wiresareobsolete.com/2014/09/building-a-recyclerview- layoutmanager-part-1/

  73. 73. Thank you! Takeshi Hagikura @thagikura

×