Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
LayoutManagerをつくろう
Search
consomme
March 10, 2017
Programming
2
3k
LayoutManagerをつくろう
DroidKaigi 2017 にて発表した資料です。
consomme
March 10, 2017
Tweet
Share
More Decks by consomme
See All by consomme
Firebaseでゼロからアプリを作る / Make app from scratch with Firebase
consomme
3
2.1k
Other Decks in Programming
See All in Programming
堅牢なフロントエンドテスト基盤を構築するために行った取り組み
shogo4131
8
2.3k
Cell-Based Architecture
larchanjo
0
110
ZOZOにおけるAI活用の現在 ~モバイルアプリ開発でのAI活用状況と事例~
zozotech
PRO
8
5.5k
안드로이드 9년차 개발자, 프론트엔드 주니어로 커리어 리셋하기
maryang
1
110
ID管理機能開発の裏側 高速にSaaS連携を実現したチームのAI活用編
atzzcokek
0
220
AIコーディングエージェント(Manus)
kondai24
0
170
WebRTC と Rust と8K 60fps
tnoho
2
2k
DSPy Meetup Tokyo #1 - はじめてのDSPy
masahiro_nishimi
1
160
Microservices rules: What good looks like
cer
PRO
0
1.2k
AtCoder Conference 2025「LLM時代のAHC」
imjk
2
410
宅宅自以為的浪漫:跟 AI 一起為自己辦的研討會寫一個售票系統
eddie
0
500
非同期処理の迷宮を抜ける: 初学者がつまづく構造的な原因
pd1xx
1
700
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
Speed Design
sergeychernyshev
33
1.4k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.4k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.8k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Designing for humans not robots
tammielis
254
26k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.7k
Music & Morning Musume
bryan
46
7k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
54k
How to Think Like a Performance Engineer
csswizardry
28
2.4k
How to train your dragon (web standard)
notwaldorf
97
6.4k
Transcript
LayoutManagerΛͭ͘Ζ͏ consomme / DroidKaigi 2017
ࣗݾհ • ͜ΜͦΊ / ࢁ࡚ ਖ਼ (Tadashi Yamazaki) • ϐΫγϒגࣜձࣾɹAndroidΞϓϦΤϯδχΞ
• Twitter : @consomme72 • Github : consomme • FGO : 071,679,396 • Nintendo Switch : SW-3116-2713-1429
Do you know pixiv ?
pixiv http://www.pixiv.net
Do you know BOOTH ?
BOOTH https://booth.pm
pixivͷ͍ΖΜͳαʔϏε
ԬʹΦϑΟε͕Ͱ͖·ͨ͠
ؒืूத https://www.wantedly.com/companies/pixiv
ΞδΣϯμ 1. RecyclerViewͱLayoutManager 2. RecyclerViewͰView͕ஔ͞ΕΔ·Ͱ 3. LayoutManagerͷத 4. LayoutManagerΛͭͬͯ͘ΈΑ͏
ҙࣄ߲ • Support Library 25.2.0 લఏͷ͓Ͱ͢ • ࠓޙόʔδϣϯΞοϓͯ͠શવҧ͏࣮ʹมΘΔՄೳੑ େ͍ʹ͋Γ·͢ •
GoogleઌੜΛ৴͡Α • ͍Ζ͍Ζઆ໌͕ෆ͍ͯͨ͠Γؒҧ͍ͬͯΔՄೳੑ ͋Γ·͢ • RecyclerViewͷίʔυશ෦ݟΔͷͱ͔ແཧ
1. RecyclerViewͱLayoutManager
RecyclerView is Կ • A flexible view for providing a
limited window into a large data set. • ڊେͳσʔληοτΛݶΒΕͨྖҬʹฒΔͨΊͷ View • ListViewGridViewͰͰ͖ͳ͔ͬͨॲཧ͕Մೳ • σʔλͷछྨͰViewΛม͑Δͱ͔͕؆୯ • Ξχϝʔγϣϯͱ͔ࣗಈͰͬͯ͘ΕΔ • ͦͷ͔ΘΓࣗલͰ͍Ζ͍Ζ༻ҙ͠ͳ͍ͱ͍͚ͳ͍ • ۠Γઢͱ͔λοϓΠϕϯτͱ͔
LayoutManager is Կ • RecyclerViewʹ͓͍ͯɺࢠViewΛͲͷΑ͏ʹஔ͢Δ ͔Λܾఆ͢Δͷ • ࢠViewͷαΠζܭࢉɺฒํɺεΫϩʔϧʹΑΔView ͷϦαΠΫϧͳͲΛ੍ޚ͍ͯ͠Δ •
LayoutManagerΛมߋ͢ΕɺRecyclerViewAdapter ͷมߋΛ͢Δ͜ͱͳ͘ϨΠΞτͷมߋ͕Մೳ • ListViewGridViewͰෆՄೳ
Ұൠతͳ RecyclerView ͷ͍ํ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new SampleRecyclerAdapter());
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͢Δ
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Ληοτ ϨΠΞτΛ࠶ඳը
AdapterͱRecycler • RecyclerView.Adapter • ࢠViewͷσʔλͷඥ͚Λߦ͏Ϋϥε • σʔλͷछྨʹΑͬͯViewHolderΛ͍͚ͯෳ ͷViewΛ͍͚Δ͜ͱ͕Մೳ • RecyclerView.Recycler
• ඇදࣔͱͳͬͨViewΛ࠶ར༻͢ΔͨΊʹอ͍࣋ͯ͠ ΔΫϥε
2. RecyclerViewͰView͕ஔ͞ΕΔ·Ͱ
RecyclerView extends ViewGroup • RecyclerViewViewGroupͷαϒΫϥεͳͷͰɺඳը ॲཧͷํ๏جຊతʹҰൠతͳViewͱಉ͡ • onMeasure ͰࢠViewͷαΠζΛܾఆ •
onLayout ͰࢠViewΛฒΔ
RecyclerViewʹ͓͚ΔࢠViewͷαΠζଌఆ • Support Library 23.2.0 ΑΓɺRecyclerViewʹ WRAP_CONTENT ͕͑ΔΑ͏ʹͳͬͨ • WRAP_CONTENT
Λ͏ʹɺLayoutManagerଆͰ setAutoMeasuredEnabled(true) Λࢦఆ͢Δඞཁ͋Γ • ٯʹݴ͑ɺ͜Ε͕trueʹͳ͍ͬͯͳ͍߹ WRAP_CONTENT ͑ͳ͍ʢϨΠΞτ่͕Ε Δʣ
setAutoMeasureEnabled ͷʑ͍͠આ໌ https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager.html#setAutoMeasureEnabled(boolean)
setAutoMeasureEnabled ͷ؆୯ͳઆ໌ • RecyclerViewLayoutManager͕ࣗಈͰViewͷαΠζΛܭࢉ͢Δ͔Ͳ ͏͔ΛܾΊΔ • trueΛηοτͨ͠߹ • ࣗಈͰViewͷαΠζܭࢉΛߦ͏ •
WRAP_CONTENT Λ༗ޮʹ͚ͨ͠Εtrueʹ͢Δ • falseΛηοτͨ͠߹ • ViewͷαΠζܭࢉ RecyclerView#onMeasure ʹॲཧΛॻ͘ • ॻ͔ͳ͍ͱView͕දࣔ͞Εͳ͍ • ΧελϚΠζͨ͠ܭࢉϩδοΫΛ͍͍ͨ߹ʹ͏ • σϑΥϧτfalseʹͳ͍ͬͯΔͷͰҙ
setAutoMeasureEnabled(true) ͷ߹ͷॲཧ 1/2 1. LayoutManager#onMeasure Λ࣮ߦ͠ɺRecyclerView ͷαΠζ͕ݻఆʢMATCH_PARENT or dpࢦఆʣͷ߹ ͦ͜Ͱऴྃ
2. αΠζ͕ܾ·͍ͬͯͳ͍߹ɺ LayoutManager#onLayoutChildren ʹͯࢠViewͷ heightͱwidthΛܭࢉ͢Δ
setAutoMeasureEnabled(true) ͷ߹ͷॲཧ 2/2 3. setMeasuredDimensionFromChildren Ͱɺ RecyclerViewͷmarginpaddingΛߟྀͯ͠width ͱheightΛܾఆ͢Δ LayoutManager#setMeasuredDimension Λoverride
ͯ͠ɺࣗಈܭࢉͱҧ͏Λઃఆ͢Δ͜ͱ͕Ͱ͖Δ 4. ܭࢉ͕ऴΘͬͨΒ RecyclerView#onLayout ͕ݺΕͯ View͕ஔ͞ΕΔ
3. LayoutManagerͷத
LayoutManagerͷओͳϝιου • abstractϝιου • generateDefaultLayoutParams • abstract͡Όͳ͍͚Ͳ࣮ඞਢͳϝιου • onLayoutChildren •
canScrollHorizontally / canScrollVertically • scrollHorizontallyBy / scrollVerticallyBy • ͦͷଞॏཁϝιου • scrollToPosition • smoothScrollToPosition
generateDefaultLayoutParams() • abstractϝιου • RecyclerViewͷࢠViewʹ͏LayoutParamsΛฦ͢ • RecyclerView.LayoutParams ͰجຊతʹOK • ΧελϜLayoutParamsΛ͏߹ɺҎԼͷϝιουΛ
override͢Δඞཁ͋Γ • checkLayoutParamsɿܕνΣοΫ • generateLayoutParamsɿϨΠΞτxml͔Βinflateͨ͠ ΓɺଞͷLayoutParamsΛίϐʔͨ͠Γ
onLayoutChildren(Recycler, State) • LayoutManagerͷ࠷ॏཁϝιου • ࢠViewͷஔɺεΫϩʔϧʹ͏ViewੜɺViewͷϦ αΠΫϧͳͲΛߦ͏ • ʮRecyclerViewͷྖҬʹʯදࣔ͢Δͯ͢ͷViewͷ ϨΠΞτॲཧΛߦ͏
• ྖҬ֎ͷͷʹ͍ͭͯScrollܥϝιουͰ
canScroll(Horizontally|Vertically)By • boolean canScrollHorizontallyBy() • boolean canScrollVerticallyBy() • ԣํʗॎํʹεΫϩʔϧͰ͖Δ͔Ͳ͏͔ •
ϨΠΞτํʹΑܾͬͯΊΔͱྑ͍
scroll(Horizontally|Vertically)By • int scrollHorizontallyBy(int, Recycler, State) • int scrollVerticallyBy(int, Recycler,
State) • ࢠViewΛԣʗॎʹҠಈ͢ΔྔΛฦ͢ • ৽͘͠ը໘ʹදࣔ͞ΕΔViewΛadd͢Δ • ը໘֎ʹফ͑ͨViewΛRecycle͢Δ
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Ληοτͯ͠ ࠶ϨΠΞτ
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); }
4. LayoutManagerΛͭͬͯ͘ΈΑ͏
खॱ 1. RecyclerView.LayoutManagerΛܧঝͨ͠ΫϥεΛ࡞Δ 2. onDefaultLayoutParams Λ࣮͢Δ 3. onLayoutManager Λ࣮͢Δ 4.
ViewͷฒํΛม͑ͯΈΔ 5. εΫϩʔϧͰ͖ΔΑ͏ʹ͢Δ
Demo https://github.com/consomme/DroidKaigi2017Sample
·ͱΊ • දࣔ͢Δ͚ͩͳΒ࣮؆୯ • onLayoutChildren ͷ࣮Λ͢Ε͘͠ͳ͍ • ͔ͦ͜ΒઌΛ࣮͢Δͷ͕͍͠ • εΫϩʔϧͱ͔ɺͦΕʹ͏ViewͷϦαΠΫϧͱ͔ɺϓ
ϦϑΣονͱ͔ɺϓϦϩʔυͱ͔… • ͍͔ʹޮతʹදࣔ͢Δ͔Λಥ͖٧ΊΔͱׂͱপ • શ෦Λཧղ͢ΔͷແཧͳͷͰɺ෦తʹগͣͭ͠ཧղΛ ਐΊΔ΄͏͕͍͍ • RecyclerViewͷιʔείʔυ12,000ߦҎ্͋Γ·͢
ʲॏཁͳͷͰ̎ݴ͍·͢ʳؒืूத https://www.wantedly.com/companies/pixiv
͋Γ͕ͱ͏͍͟͝·ͨ͠