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

LayoutManagerをつくろう

225a1d1ad7dad206b80479dd232639ed?s=47 consomme
March 10, 2017

 LayoutManagerをつくろう

DroidKaigi 2017 にて発表した資料です。

225a1d1ad7dad206b80479dd232639ed?s=128

consomme

March 10, 2017
Tweet

Transcript

  1. LayoutManagerΛͭ͘Ζ͏ consomme / DroidKaigi 2017

  2. ࣗݾ঺հ • ͜ΜͦΊ / ࢁ࡚ ਖ਼ (Tadashi Yamazaki) • ϐΫγϒגࣜձࣾɹAndroidΞϓϦΤϯδχΞ

    • Twitter : @consomme72 • Github : consomme • FGO : 071,679,396 • Nintendo Switch : SW-3116-2713-1429
  3. Do you know pixiv ?

  4. pixiv http://www.pixiv.net

  5. Do you know BOOTH ?

  6. BOOTH https://booth.pm

  7. pixivͷ͍ΖΜͳαʔϏε

  8. ෱ԬʹΦϑΟε͕Ͱ͖·ͨ͠

  9. ஥ؒืूத https://www.wantedly.com/companies/pixiv

  10. ΞδΣϯμ 1. RecyclerViewͱLayoutManager 2. RecyclerViewͰView͕഑ஔ͞ΕΔ·Ͱ 3. LayoutManagerͷத਎ 4. LayoutManagerΛͭͬͯ͘ΈΑ͏

  11. ஫ҙࣄ߲ • Support Library 25.2.0 લఏͷ͓࿩Ͱ͢ • ࠓޙόʔδϣϯΞοϓͯ͠શવҧ͏࣮૷ʹมΘΔՄೳੑ ͸େ͍ʹ͋Γ·͢ •

    GoogleઌੜΛ৴͡Α • ͍Ζ͍Ζઆ໌͕ෆ଍͍ͯͨ͠Γؒҧ͍ͬͯΔՄೳੑ΋ ͋Γ·͢ • RecyclerViewͷίʔυશ෦ݟΔͷͱ͔ແཧ
  12. 1. RecyclerViewͱLayoutManager

  13. RecyclerView is Կ • A flexible view for providing a

    limited window into a large data set. • ڊେͳσʔληοτΛݶΒΕͨྖҬ಺ʹฒ΂ΔͨΊͷ View • ListView΍GridViewͰ͸Ͱ͖ͳ͔ͬͨॲཧ͕Մೳ • σʔλͷछྨͰViewΛม͑Δͱ͔͕؆୯ • Ξχϝʔγϣϯͱ͔΋ࣗಈͰ΍ͬͯ͘ΕΔ • ͦͷ͔ΘΓࣗલͰ͍Ζ͍Ζ༻ҙ͠ͳ͍ͱ͍͚ͳ͍ • ۠੾Γઢͱ͔λοϓΠϕϯτͱ͔
  14. LayoutManager is Կ • RecyclerViewʹ͓͍ͯɺࢠViewΛͲͷΑ͏ʹ഑ஔ͢Δ ͔Λܾఆ͢Δ΋ͷ • ࢠViewͷαΠζܭࢉɺฒ΂ํɺεΫϩʔϧʹΑΔView ͷϦαΠΫϧͳͲΛ੍ޚ͍ͯ͠Δ •

    LayoutManagerΛมߋ͢Ε͹ɺRecyclerView΍Adapter ͷมߋΛ͢Δ͜ͱͳ͘ϨΠΞ΢τͷมߋ͕Մೳ • ListView΍GridViewͰ͸ෆՄೳ
  15. Ұൠతͳ RecyclerView ͷ࢖͍ํ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
 recyclerView.setLayoutManager(new LinearLayoutManager(this));


    recyclerView.setAdapter(new SampleRecyclerAdapter());
  16. setLayoutManager(LayoutManager) 1/2 public void setLayoutManager(LayoutManager layout) {
 if (layout ==

    mLayout) {
 return;
 }
 stopScroll();
 if (mLayout != null) {
 if (mItemAnimator != null) {
 mItemAnimator.endAnimations();
 }
 mLayout.removeAndRecycleAllViews(mRecycler);
 mLayout.removeAndRecycleScrapInt(mRecycler);
 mRecycler.clear();
 
 if (mIsAttached) {
 mLayout.dispatchDetachedFromWindow(this, mRecycler);
 }
 mLayout.setRecyclerView(null);
 mLayout = null;
 } else {
 mRecycler.clear();
 } εΫϩʔϧΛࢭΊΔ ΞχϝʔγϣϯΛࢭΊΔ ࢠ7JFXΛ͢΂ͯফ͢ EFUBDI͢Δ
  17. setLayoutManager(LayoutManager) 2/2 mChildHelper.removeAllViewsUnfiltered();
 mLayout = layout;
 if (layout != null)

    {
 if (layout.mRecyclerView != null) {
 throw new IllegalArgumentException("LayoutManager " + layout +
 " is already attached to a RecyclerView: " + layout.mRecyclerView);
 }
 mLayout.setRecyclerView(this);
 if (mIsAttached) {
 mLayout.dispatchAttachedToWindow(this);
 }
 }
 mRecycler.updateViewCacheSize();
 requestLayout();
 } -BZPVU.BOBHFSʹ 3FDZDMFS7JFXΛηοτ 3FDZDMFS7JFXʹ -BZPVU.BOBHFSΛηοτ ϨΠΞ΢τΛ࠶ඳը
  18. AdapterͱRecycler • RecyclerView.Adapter • ࢠView΁ͷσʔλͷඥ෇͚Λߦ͏Ϋϥε • σʔλͷछྨʹΑͬͯViewHolderΛ࢖͍෼͚ͯෳ਺ ͷViewΛ࢖͍෼͚Δ͜ͱ͕Մೳ • RecyclerView.Recycler

    • ඇදࣔͱͳͬͨViewΛ࠶ར༻͢ΔͨΊʹอ͍࣋ͯ͠ ΔΫϥε
  19. 2. RecyclerViewͰView͕഑ஔ͞ΕΔ·Ͱ

  20. RecyclerView extends ViewGroup • RecyclerView͸ViewGroupͷαϒΫϥεͳͷͰɺඳը ॲཧͷํ๏͸جຊతʹҰൠతͳViewͱಉ͡ • onMeasure ͰࢠViewͷαΠζΛܾఆ •

    onLayout ͰࢠViewΛฒ΂Δ
  21. RecyclerViewʹ͓͚ΔࢠViewͷαΠζଌఆ • Support Library 23.2.0 ΑΓɺRecyclerViewʹ WRAP_CONTENT ͕࢖͑ΔΑ͏ʹͳͬͨ • WRAP_CONTENT

    Λ࢖͏ʹ͸ɺLayoutManagerଆͰ setAutoMeasuredEnabled(true) Λࢦఆ͢Δඞཁ͋Γ • ٯʹݴ͑͹ɺ͜Ε͕trueʹͳ͍ͬͯͳ͍৔߹͸ WRAP_CONTENT ͸࢖͑ͳ͍ʢϨΠΞ΢τ่͕Ε Δʣ
  22. setAutoMeasureEnabled ͷ௕ʑ͍͠આ໌ https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager.html#setAutoMeasureEnabled(boolean)

  23. setAutoMeasureEnabled ͷ؆୯ͳઆ໌ • RecyclerView΍LayoutManager͕ࣗಈͰViewͷαΠζΛܭࢉ͢Δ͔Ͳ ͏͔ΛܾΊΔ • trueΛηοτͨ͠৔߹ • ࣗಈͰViewͷαΠζܭࢉΛߦ͏ •

    WRAP_CONTENT Λ༗ޮʹ͚ͨ͠Ε͹trueʹ͢Δ • falseΛηοτͨ͠৔߹ • ViewͷαΠζܭࢉ͸ RecyclerView#onMeasure ʹॲཧΛॻ͘ • ॻ͔ͳ͍ͱView͕දࣔ͞Εͳ͍ • ΧελϚΠζͨ͠ܭࢉϩδοΫΛ࢖͍͍ͨ৔߹ʹ࢖͏ • σϑΥϧτ஋͸falseʹͳ͍ͬͯΔͷͰ஫ҙ
  24. setAutoMeasureEnabled(true) ͷ৔߹ͷॲཧ 1/2 1. LayoutManager#onMeasure Λ࣮ߦ͠ɺRecyclerView ͷαΠζ͕ݻఆʢMATCH_PARENT or dpࢦఆʣͷ৔߹ ͸ͦ͜Ͱऴྃ

    2. αΠζ͕ܾ·͍ͬͯͳ͍৔߹͸ɺ LayoutManager#onLayoutChildren ʹͯࢠViewͷ heightͱwidthΛܭࢉ͢Δ
  25. setAutoMeasureEnabled(true) ͷ৔߹ͷॲཧ 2/2 3. setMeasuredDimensionFromChildren Ͱɺ RecyclerViewͷmargin΍padding౳Λߟྀͯ͠width ͱheightΛܾఆ͢Δ LayoutManager#setMeasuredDimension Λoverride

    ͯ͠ɺࣗಈܭࢉͱҧ͏஋Λઃఆ͢Δ͜ͱ͕Ͱ͖Δ 4. ܭࢉ͕ऴΘͬͨΒ RecyclerView#onLayout ͕ݺ͹Εͯ View͕഑ஔ͞ΕΔ
  26. 3. LayoutManagerͷத਎

  27. LayoutManagerͷओͳϝιου • abstractϝιου • generateDefaultLayoutParams • abstract͡Όͳ͍͚Ͳ࣮૷ඞਢͳϝιου • onLayoutChildren •

    canScrollHorizontally / canScrollVertically • scrollHorizontallyBy / scrollVerticallyBy • ͦͷଞॏཁϝιου • scrollToPosition • smoothScrollToPosition
  28. generateDefaultLayoutParams() • abstractϝιου • RecyclerViewͷࢠViewʹ࢖͏LayoutParamsΛฦ͢ • RecyclerView.LayoutParams Ͱجຊతʹ͸OK • ΧελϜLayoutParamsΛ࢖͏৔߹ɺҎԼͷϝιουΛ

    override͢Δඞཁ͋Γ • checkLayoutParamsɿܕνΣοΫ • generateLayoutParamsɿϨΠΞ΢τxml͔Βinflateͨ͠ ΓɺଞͷLayoutParamsΛίϐʔͨ͠Γ
  29. onLayoutChildren(Recycler, State) • LayoutManagerͷ࠷ॏཁϝιου • ࢠViewͷ഑ஔɺεΫϩʔϧʹ൐͏Viewੜ੒ɺViewͷϦ αΠΫϧͳͲΛߦ͏ • ʮRecyclerViewͷྖҬ಺ʹʯදࣔ͢Δ͢΂ͯͷViewͷ ϨΠΞ΢τॲཧΛߦ͏

    • ྖҬ֎ͷ΋ͷʹ͍ͭͯ͸ScrollܥϝιουͰ
  30. canScroll(Horizontally|Vertically)By • boolean canScrollHorizontallyBy() • boolean canScrollVerticallyBy() • ԣํ޲ʗॎํ޲ʹεΫϩʔϧͰ͖Δ͔Ͳ͏͔ •

    ϨΠΞ΢τํ޲ʹΑܾͬͯΊΔͱྑ͍
  31. scroll(Horizontally|Vertically)By • int scrollHorizontallyBy(int, Recycler, State) • int scrollVerticallyBy(int, Recycler,

    State) • ࢠViewΛԣʗॎʹҠಈ͢ΔྔΛฦ͢ • ৽͘͠ը໘಺ʹදࣔ͞ΕΔViewΛadd͢Δ • ը໘֎ʹফ͑ͨViewΛRecycle͢Δ
  32. scrollToPosition(int) • RecyclerView#scrollToPosition ͷ࣌ʹݺ͹ΕΔ • positionΛηοτͯ͠ϨΠΞ΢τ͠௚ͤ͹OK ※LinearLayoutMangerͷ࣮૷ @Override
 public void

    scrollToPosition(int position) {
 mPendingScrollPosition = position;
 mPendingScrollPositionOffset = INVALID_OFFSET;
 if (mPendingSavedState != null) {
 mPendingSavedState.invalidateAnchor();
 }
 requestLayout();
 } QPTJUJPOΛηοτͯ͠ ࠶౓ϨΠΞ΢τ
  33. smoothScrollToPosition(RecyclerView, State, int) • RecyclerView#smoothScrollToPosition ͷ࣌ʹݺ͹ΕΔ • smooth scrollingΛαϙʔτ͍ͨ࣌͠ʹ࣮૷͢Δ •

    RecyclerView.SmoothScroller ͷΠϯελϯεΛ࡞Γɺ startSmoothScroll ʹ౉͢ ※LinearLayoutMangerͷ࣮૷ @Override
 public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
 int position) {
 LinearSmoothScroller linearSmoothScroller =
 new LinearSmoothScroller(recyclerView.getContext());
 linearSmoothScroller.setTargetPosition(position);
 startSmoothScroll(linearSmoothScroller);
 }
  34. 4. LayoutManagerΛͭͬͯ͘ΈΑ͏

  35. खॱ 1. RecyclerView.LayoutManagerΛܧঝͨ͠ΫϥεΛ࡞Δ 2. onDefaultLayoutParams Λ࣮૷͢Δ 3. onLayoutManager Λ࣮૷͢Δ 4.

    Viewͷฒ΂ํΛม͑ͯΈΔ 5. εΫϩʔϧͰ͖ΔΑ͏ʹ͢Δ
  36. Demo https://github.com/consomme/DroidKaigi2017Sample

  37. ·ͱΊ • දࣔ͢Δ͚ͩͳΒ࣮͸؆୯ • onLayoutChildren ͷ࣮૷Λ޻෉͢Ε͹೉͘͠ͳ͍ • ͔ͦ͜ΒઌΛ࣮૷͢Δͷ͕೉͍͠ • εΫϩʔϧͱ͔ɺͦΕʹ൐͏ViewͷϦαΠΫϧͱ͔ɺϓ

    ϦϑΣονͱ͔ɺϓϦϩʔυͱ͔… • ͍͔ʹޮ཰తʹදࣔ͢Δ͔Λಥ͖٧ΊΔͱׂͱপ • શ෦Λཧղ͢Δͷ͸ແཧͳͷͰɺ෦෼తʹগͣͭ͠ཧղΛ ਐΊΔ΄͏͕͍͍ • RecyclerViewͷιʔείʔυ͸12,000ߦҎ্͋Γ·͢
  38. ʲॏཁͳͷͰ̎౓ݴ͍·͢ʳ஥ؒืूத https://www.wantedly.com/companies/pixiv

  39. ͋Γ͕ͱ͏͍͟͝·ͨ͠