Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
それっぽいカルーセルをつくる
Search
Yoshihiro WADA
December 13, 2018
Programming
4
720
それっぽいカルーセルをつくる
2018/12/13に開催された Shibuya.apk #30 にて発表した資料です
Yoshihiro WADA
December 13, 2018
Tweet
Share
More Decks by Yoshihiro WADA
See All by Yoshihiro WADA
AndroidデバイスにFTPサーバを建立する
e10dokup
0
420
Gradleの実行環境設定を見直す
e10dokup
0
1k
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
0
630
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.2k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
740
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
3.7k
今更「dp」を考える / Let's think about "dp" now
e10dokup
0
5.7k
1から学ぶAndroidアプリデバッグ - アプリの動作を追いかけよう / Learn Android application debugging from the scratch - track apps' behaviors
e10dokup
10
3.3k
Guide to background processingを読んでみる / Reading "Guide to background processing"
e10dokup
0
260
Other Decks in Programming
See All in Programming
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
220
すべてのコンテキストを、 ユーザー価値に変える
applism118
4
1.4k
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
590
What's new in AppKit on macOS 26
1024jp
0
140
テストから始めるAgentic Coding 〜Claude Codeと共に行うTDD〜 / Agentic Coding starts with testing
rkaga
15
5.3k
20250708_JAWS_opscdk
takuyay0ne
2
120
生成AI時代のコンポーネントライブラリの作り方
touyou
1
260
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
2
14k
AIともっと楽するE2Eテスト
myohei
8
2.9k
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
330
チームで開発し事業を加速するための"良い"設計の考え方 @ サポーターズCoLab 2025-07-08
agatan
1
450
初学者でも今すぐできる、Claude Codeの生産性を10倍上げるTips
s4yuba
16
12k
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
980
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Done Done
chrislema
184
16k
The World Runs on Bad Software
bkeepers
PRO
69
11k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.9k
Site-Speed That Sticks
csswizardry
10
700
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.5k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.4k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
510
Practical Orchestrator
shlominoach
189
11k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Transcript
それっぽいカルーセルを作る Cyber Agent Inc. Yoshihiro Wada a.k.a. @e10dokup 2018/12/13 Shibuya.apk
自己紹介 • Yoshihiro Wada a.k.a. @e10dokup • 大体右のアイコンで息をしています • CyberAgant
Inc. / Ameba • Amebaブログやってます • We’re Hiring • カメラ沼 • 財布の透過率が高いのが最近の悩み
今日のコンテンツ • カルーセルを作る • ループするしないとかするとかいろいろあるが… • 今回は画面横方向に面が並んだものと定義します • 正直EpoxyにCarouselItemってあるやん…? 2
1 3 4
特に… • 画面横幅いっぱいにコンテンツアイテムとかを出すスナップで行き来できるカルーセル • マージンがついたり • 触っていないときは隣の面が見えるように…とかだったり • 今回はRecyclerViewで実装していきます(ViewPager) •
本音:Groupieで雑にAdapterを作って管理したかった 2 1 3
やっていきましょう
レベル1 単純に画面いっぱいのカルーセル
どうということはない • RecyclerViewに対してlayout_widthがmatch_parentなItemのLayoutを用意する • Adapterにはそのレイアウトを渡してInflateさせる • SnapHelperにRecyclerViewを渡してスナップによるスクロールをさせるようにする
SnapHelper • RecyclerView.onFlingListenerを継承したAbstract class • フリングしたときに子Viewにスナップさせる • 継承クラスは2つ • LinearSnapHelper
• snap対象のViewがRecyclerViewの中心に来るようにスナップ • PagerSnapHelper • ViewPagerっぽい挙動のスナップ • SnapHelper#attachToRecyclerView(recyclerView)でアタッチ • nullを入れるとdetach。多重attachしないように気をつける
レイアウトを用意して <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="150dp" android:background="#EEEEEE"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" ɾɾɾ/>
</android.support.constraint.ConstraintLayout>
RecyclerViewにAdapterをセットする // container͕RecyclerViewͰ͢ adapter = RecyclerAdapter(list) // onDestroyͳΓͰdetach͢Δ snapHelper.attachToRecyclerView(container) container.setHasFixedSize(true)
container.layoutManager = LinearLayoutManager( this, LinearLayoutManager.HORIZONTAL, // ਫฏํͳͷͰ… false) container.adapter = adapter
レベル2 アイテム間にスペースを つけるカルーセル
Spaceを入れるItemDecorationをつけよう • getItemOffsetsをoverrideしたItemDecorationを用意する • 引数のoutRectのleft/rightを必要なspace分ずらす • 実装したItemDecorationをRecyclerViewにaddするだけ container.addItemDecoration(SpaceItemDecoration(SPACE_SIZE))
ItemDecorationの中はこんな感じ override fun getItemOffsets( outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State) { outRect.set(0, 0, space, 0) // ඞཁͳϚʔδϯΛηοτ // outRect.right = space ͱ͔ͰOKɻͨͩ͠pxͳͷͰdp -> px͢Δ }
なんか左寄りなので真ん中にしたい override fun getItemOffsets( outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State) { // ࠨӈۉʹϚʔδϯ͕ͨΔΑ͏ʹ͢Δ outRect.set(space / 2, 0, space / 2, 0) }
良さそう ちゃんと真ん中に寄ってる
レベル3 隣のアイテムが見えるカルーセル
やりたいことは… • 触っていないときは隣のアイテムが見えている状態にしたい • 画面幅に対して左右60dpずつマージンをとる • itemが並ぶ間隔はマージンの半分である30dpにする 2 3 1
60dp 30dp
変えないといけないこと • 元々がwidthがmatch_parentなので、このままではいくらItemDecorationでOffsetをつけて も隣のViewは同じようには見えない • OffsetでItemのサイズが変わるので無理やり一つ見えてもほかのサイズが変わったり… • アイテム自体を固定値に…できたら良かった • 世の中の端末すべてが横幅360dpではない
• 隣のアイテムが見える + アイテムが中央に来るは達成できるが… • 端末によっては中央にアイテムが来るように調整した結果 余白が大きくスカスカに見える • Eg. Nexus 5X -> 411dp、Essential PH-1 -> 431dp…
つまり… • match_parent時にしたときのitemのサイズを制限できればいい • ということは親が小さくなればいい • 親になるRecyclerView自体にPaddingを設定する
少し算数する • アイテム間のスペースが30dpの時、RecyclerViewのPaddingを60dpにして、かつ中央にア イテムが来るような値のとり方を考える • 前述の通り、アイテムの中央寄せの為に左右に同じスペースをとる • つまりアイテムの左右には15dpを与える • 最初のアイテムも左側には15dp持つことになるので、Paddingを安直に60dpにすると75dp
になる。ここは60dpで抑えたい • よってRecyclerView取るべきPaddingは60-15=45dp 2 3 1 60dp 30dp
少し算数する(一般化) • アイテム間のスペースがx[dp]の時、RecyclerViewのPaddingを2x[dp]にして、かつ中央に アイテムが来るような値のとり方を考える • 前述の通り、アイテムの中央寄せの為に左右に同じスペースをとる • つまりアイテムの左右には0.5x[dp]を与える • 最初のアイテムも左側には0.5x[dp]持つことになるので、Paddingを安直に2x[dp]にすると
2.5x[dp]になる。ここは2x[dp]で抑えたい • よってRecyclerViewが取るべきPaddingは2x-0.5x=1.5x[dp] • XML上に書いてもItemDecorationには反映されないのでこれをコードで定義する • SpaceItemDecorationを作る際に一緒にRecyclerViewを引数に渡してみる
いい感じにマージンを設定する fun from( recyclerView: RecyclerView, itemSpaceDp: Int ): SpaceItemDecoration {
val paddingPx = itemSpaceDp.toPx() // ͍͍ײ͡ʹdp -> pxม // RecyclerViewʹ༩͑Δpaddingʢ1.5x[dp]Λ༻ҙ͢Δʣ val edgePaddingPx = (paddingPx * 3 / 2).toInt() recyclerView.setPadding(edgePaddingPx, 0, edgePaddingPx, 0) return SpaceItemDecoration(paddingPx.toInt()) }
やったか…? 隣が見えていない (´・ω・`)
つまり… • match_parent時にしたときのitemのサイズを制限できればいい • ということは親が小さくなればいい • 親になるRecyclerView自体にPaddingを設定する • RecyclerView自体にPaddingをつけても隣は結局見えない
つまり… • match_parent時にしたときのitemのサイズを制限できればいい • ということは親が小さくなればいい • 親になるRecyclerView自体にPaddingを設定する • RecyclerView自体にPaddingをつけても隣は結局見えない •
clipToPaddingをfalseにすることで見えるようになる • デフォルトではPaddingによる余白の描画は切り取るようになっているがそれを表示する • paddingされたコンテンツの外側にあるものが見えるようになる
いい感じにマージンを設定する fun from( recyclerView: RecyclerView, itemSpaceDp: Int ): SpaceItemDecoration {
val paddingPx = itemSpaceDp.toPx() // ͍͍ײ͡ʹdp -> pxม // RecyclerViewʹ༩͑Δpaddingʢ1.5x[dp]Λ༻ҙ͢Δʣ val edgePaddingPx = (paddingPx * 3 / 2).toInt() recyclerView.setPadding(edgePaddingPx, 0, edgePaddingPx, 0) recyclerView.clipToPadding = false // ͜ΕͰྡ͕ݟ͑Δ return SpaceItemDecoration(paddingPx.toInt()) }
良さそう ちゃんと隣も見えていて 中央に寄ってる
まとめ • RecyclerViewでいろんなカルーセルを作る話でした • 結局作りたかったのは「隣のitemがちらっと見えるカルーセル」 • 今回は「画面幅に対するPaddingの半分の間隔でitemが並んでいる時」の話なので デザインで異なる場合はそれにあった算数が必要 • EpoxyのCarouselItemを使うと
setItemSpacingPx でアイテム間のスペースを 設定できるのでItemDecorationを書かなくてもなんとかなるのかな • 未検証です
ありがとうございました