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
700
それっぽいカルーセルをつくる
2018/12/13に開催された Shibuya.apk #30 にて発表した資料です
Yoshihiro WADA
December 13, 2018
Tweet
Share
More Decks by Yoshihiro WADA
See All by Yoshihiro WADA
Gradleの実行環境設定を見直す
e10dokup
0
810
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
0
540
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.1k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
700
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
3.4k
今更「dp」を考える / Let's think about "dp" now
e10dokup
0
5.5k
1から学ぶAndroidアプリデバッグ - アプリの動作を追いかけよう / Learn Android application debugging from the scratch - track apps' behaviors
e10dokup
10
3.1k
Guide to background processingを読んでみる / Reading "Guide to background processing"
e10dokup
0
250
よしなに頑張る画像ロードの話 / image load mettya tsurai
e10dokup
2
480
Other Decks in Programming
See All in Programming
Scaling your build logic
antalmonori
1
100
Beyond ORM
77web
11
1.6k
watsonx.ai Dojo #6 継続的なAIアプリ開発と展開
oniak3ibm
PRO
0
170
return文におけるstd::moveについて
onihusube
1
1.4k
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
1.3k
Amazon Nova Reelの可能性
hideg
0
200
20241217 競争力強化とビジネス価値創出への挑戦:モノタロウのシステムモダナイズ、開発組織の進化と今後の展望
monotaro
PRO
0
290
ドメインイベント増えすぎ問題
h0r15h0
2
570
ゼロからの、レトロゲームエンジンの作り方
tokujiros
3
1.1k
Simple組み合わせ村から大都会Railsにやってきた俺は / Coming to Rails from the Simple
moznion
3
2.2k
chibiccをCILに移植した結果 (NGK2025S版)
kekyo
PRO
0
140
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
190
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Producing Creativity
orderedlist
PRO
343
39k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
870
Visualization
eitanlees
146
15k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
Building Your Own Lightsaber
phodgson
104
6.2k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
240
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
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を書かなくてもなんとかなるのかな • 未検証です
ありがとうございました