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
Contact AppっぽいSticky Headerをつくる
Search
Yoshihiro WADA
February 22, 2018
Programming
3
930
Contact AppっぽいSticky Headerをつくる
2018/02/22に開催されたpotatotips #48での発表スライドです。
Yoshihiro WADA
February 22, 2018
Tweet
Share
More Decks by Yoshihiro WADA
See All by Yoshihiro WADA
AndroidデバイスにFTPサーバを建立する
e10dokup
0
250
Gradleの実行環境設定を見直す
e10dokup
0
850
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
0
560
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.1k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
710
[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
Other Decks in Programming
See All in Programming
AIの力でお手軽Chrome拡張機能作り
taiseiue
0
170
定理証明プラットフォーム lapisla.net
abap34
1
1.8k
法律の脱レガシーに学ぶフロントエンド刷新
oguemon
5
740
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
120
ソフトウェアエンジニアの成長
masuda220
PRO
10
1.1k
動作確認やテストで漏れがちな観点3選
starfish719
6
1k
Pythonでもちょっとリッチな見た目のアプリを設計してみる
ueponx
1
560
ファインディLT_ポケモン対戦の定量的分析
fufufukakaka
0
710
GAEログのコスト削減
mot_techtalk
0
120
SwiftUI Viewの責務分離
elmetal
PRO
1
230
Lottieアニメーションをカスタマイズしてみた
tahia910
0
130
社内フレームワークとその依存性解決 / in-house framework and its dependency management
vvakame
1
560
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
Docker and Python
trallard
44
3.3k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.2k
The World Runs on Bad Software
bkeepers
PRO
67
11k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
410
A better future with KSS
kneath
238
17k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
27
1.6k
Scaling GitHub
holman
459
140k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
9
440
Transcript
Contact App っぽい Sticky Header をつくる Yoshihiro Wada a.k.a. @e10dokup
2018/02/22 @ potatotips #48
自己紹介 Yoshihiro Wada CyberAgent, Inc. でいろいろやったりやらなかったり @e10dokup
作りたい物 Android の Contact App や droidkaigi-conference-app みたいな 「名前一覧のアレ」
つかうもの 3FDZDMFS7JFX*UFN%FDPSBUJPO 3 つのメソッドを Override する RecyclerView のアイテムに対して装飾をする adstract class
divider の線を引いたりアイテム間のドラッグをしたり… HFU*UFN0GGTFUT 3FDUPVU3FDU 7JFXWJFX 3FDZDMFS7JFXQBSFOU 3FDZDMFS7JFX4UBUFTUBUF PO%SBX $BOWBTD 3FDZDMFS7JFXQBSFOU 3FDZDMFS7JFX4UBUFTUBUF PO%SBX0WFS $BOWBTD 3FDZDMFS7JFXQBSFOU 3FDZDMFS7JFX4UBUFTUBUF
HFU*UFN0GGTFUT RecyclerView の各 Item の描画位置をずらすメソッド 第一引数の outRect をいじることで描画位置をずらすことができる item の
parent ごと弄るイメージなので item 側の layout XML は outRect の中で描画されることになる 今回作りたい Sticky Header の場合だと left の座標を作りたいマージン分 加えるだけで良さそう。
PO%SBXPO%SBX0WFS Decoration の描画時 / 描画後に呼ばれるメソッド 第一引数の c (Canvas) を操作することで装飾を描画できる この
Canvas は RecyclerView 全体の Canvas で、 RecyclerView の再描画 毎に 1 回だけ呼び出される 今回作りたい Sticky Header の場合だと表示されている要素をループで 見ながら頭文字を DESBX5FYU で然る場所に描画したら良さそう
Canvas 上に文字を書く DBOWBTESBX5FYU 'POU.FUSJDT 指定した座標に指定した 'POU.FUSJDT で文字列を描画するメソッド 指定した座標が中央ではないので補正してあげる必要がある 5FYU1BJOU に対し色やフォントサイズを決定した後、
HFU'POU.FUSJDT で取得する abcdfeghi (0,0) top ascent leading descent bottom ※原点は 5FYU1BJOUUFYU"MJHO1BJOU"MJHO-&'5 の場合
ItemDecoration を実装する (下準備) リスト要素からラベルに表示したい文字 (大体頭文字) を取り出して渡す interface を用意しておく JOUFSGBDF$BMMCBDL\ GVOHFU*OJUJBM
QPTJUJPO*OU 4USJOH ^ ӊҮӉҮ JOUFSGBDF Әᇴ⸢әҽӽӔᖚӂ㮢6QQFS$BTF Ӓҵә⢰ᗍӁӐҮӔҮ㮣 PCKFDU4UJDLZ-BCFM*UFN%FDPSBUJPO$BMMCBDL\ PWFSSJEFGVOHFU*OJUJBM QPTJUJPO*OU 4USJOH\ SFUVSOJUFNT<QPTJUJPO>OBNF<>UP4USJOH ^ ^ ESPQXIJMF とか UP6QQFS$BTF を使うといい感じに @ を 省いたり大文字小文字を揃えたりできそう
ItemDecoration を実装する (初期化) 初期化中に 'POU.FUSJDT と要素の margin、 ラベルの padding を
設定する。 今回は Context を拾って resource から引く感じ JOJU\ WBMSFTPVSDFDPOUFYUSFTPVSDFT 5FYU1BJOU Ә⼀ᇰ UFYU1BJOUBQQMZ\ UZQFGBDF5ZQFGBDF%&'"6-5 JT"OUJ"MJBTUSVF UFYU4J[FSFTPVSDFHFU%JNFOTJPO 3EJNFOTUJDLZ@MBCFM@GPOU@TJ[F DPMPS$POUFYU$PNQBUHFU$PMPS DPOUFYU 3DPMPSQSJNBSZ UFYU"MJHO1BJOU"MJHO-&'5 ^ ൵ኃᓬӘᴀᇰ GPOU.FUSJDTUFYU1BJOUGPOU.FUSJDT MBCFM1BEEJOHSFTPVSDFHFU%JNFOTJPO1JYFM4J[F 3EJNFOMBCFM@QBEEJOH DPOUFOU.BSHJOSFTPVSDFHFU%JNFOTJPO1JYFM4J[F 3EJNFODPOUFOU@NBSHJO ^
ItemDecoration を実装する (HFU*UFN0GGTFUT) init で得た contentMargin の分だけ outRect の left
を増加させ、 ラベルが入る場所を作る PWFSSJEFGVOHFU*UFN0GGTFUT PVU3FDU3FDU WJFX7JFX QBSFOU3FDZDMFS7JFX TUBUF3FDZDMFS7JFX4UBUF \ TVQFSHFU*UFN0GGTFUT PVU3FDU WJFX QBSFOU TUBUF PVU3FDUMFGUDPOUFOU.BSHJO ^ このままだとラベルを与えたい要素以外も全部左にマージンが入るので Callback.getInitial() に不正な値が入ったときはマージンを与えない等 すると本来ラベル与えたい要素以外は画面前幅に描画される 全幅
ItemDecoration を実装する (PO%SBX) PWFSSJEFGVOPO%SBX D$BOWBT QBSFOU3FDZDMFS7JFX TUBUF3FDZDMFS7JFX4UBUF \ TVQFSPO%SBX D
QBSFOU TUBUF WBMUPUBM*UFN$PVOUTUBUFJUFN$PVOUᩈ✊ӁӐҮӵ⺙✛ᡔ WBMDIJME$PVOUQBSFOUDIJME$PVOUজⷭ⒈ҿӶӐҮӵ⺙✛ᡔ WBMGPOU$FOUFS GPOU.FUSJDTBTDFOU GPOU.FUSJDTEFTDFOU WBSQSFWJPVT*OJUJBM4USJOH WBSJOJUJBM GPS JJOVOUJMDIJME$PVOU \ ⷭ⒈ҿӶӐҮӵ⺙✛ҶՑՁՓӼᝡ∈Ӄӣҷ⺙✛ҵᴀᇰӃӵ WBMWJFXQBSFOUHFU$IJME"U J WBMQPTJUJPOQBSFOUHFU$IJME"EBQUFS1PTJUJPO WJFX QSFWJPVT*OJUJBMJOJUJBM JOJUJBMDBMMCBDLHFU*OJUJBM QPTJUJPO JG 5FYU6UJMTJT&NQUZ JOJUJBM ]]QSFWJPVT*OJUJBMJOJUJBM DPOUJOVF ᝡ∈৴⡕Ә : ᏍᮏӼᴀᇰӁӐᝡ∈Ӄӵ㮢ᰪՂդԠ㮣 ^ ^
ItemDecoration を実装する (PO%SBX) PWFSSJEFGVOPO%SBX D$BOWBT QBSFOU3FDZDMFS7JFX TUBUF3FDZDMFS7JFX4UBUF \ TVQFSPO%SBX D
QBSFOU TUBUF WBMUPUBM*UFN$PVOUTUBUFJUFN$PVOU ᩈ✊ӁӐҮӵ⺙✛ᡔ WBMDIJME$PVOUQBSFOUDIJME$PVOUজⷭ⒈ҿӶӐҮӵ⺙✛ᡔ WBMGPOU$FOUFS GPOU.FUSJDTBTDFOU GPOU.FUSJDTEFTDFOU WBSQSFWJPVT*OJUJBM4USJOH WBSJOJUJBM GPS JJOVOUJMDIJME$PVOU \ ⷭ⒈ҿӶӐҮӵ⺙✛ҶՑՁՓӼᝡ∈Ӄӣҷ⺙✛ҵᴀᇰӃӵ WBMWJFXQBSFOUHFU$IJME"U J WBMQPTJUJPOQBSFOUHFU$IJME"EBQUFS1PTJUJPO WJFX QSFWJPVT*OJUJBMJOJUJBM JOJUJBMDBMMCBDLHFU*OJUJBM QPTJUJPO JG 5FYU6UJMTJT&NQUZ JOJUJBM ]]QSFWJPVT*OJUJBMJOJUJBM DPOUJOVF ᝡ∈৴⡕Ә : ᏍᮏӼᴀᇰӁӐᝡ∈Ӄӵ㮢ᰪՂդԠ㮣 ^ ^ リストの前要素と initial が 一致するときは描画しない 描画するのは同じ initial の 先頭の要素だけ
ItemDecoration を実装する (実際の描画) ラベルを描画すべきと判定した要素について描画位置の Y 座標を決定して c.DrawText() で描画する ᇴ㗖Ә 'POU.FUSJDT
ӘसႠᏍᮏ㮢నՂդԠҵӳᛝӍӐҷӉӊһ㮣 WBMGPOU$FOUFS GPOU.FUSJDTBTDFOU GPOU.FUSJDTEFTDFOU ᇴ㗖Әᝡ∈ⅈ WBMWJFX$FOUFS WJFXUPQ WJFXCPUUPN WBMWJFX.JEEMFWJFXIFJHIU WBSUFYU:.BUINBY WJFX.JEEMF WJFX$FOUFS GPOU$FOUFS JG QPTJUJPO UPUBM*UFN$PVOU \ WBMOFYU*OJUJBMDBMMCBDLHFU*OJUJBM QPTJUJPO JG OFYU*OJUJBMJOJUJBMWJFX$FOUFSWJFX.JEEMF \ UFYU:WJFX.JEEMFWJFX$FOUFS ^ ^ DESBX5FYU JOJUJBM MBCFM1BEEJOHUP'MPBU UFYU: UFYU1BJOU
ItemDecoration を実装する (実際の描画) ラベルを描画すべきと判定した要素について描画位置の Y 座標を決定して c.DrawText() で描画する ᇴ㗖Ә 'POU.FUSJDT
ӘसႠᏍᮏ㮢నՂդԠҵӳᛝӍӐҷӉӊһ㮣 WBMGPOU$FOUFS GPOU.FUSJDTBTDFOU GPOU.FUSJDTEFTDFOU ᇴ㗖Әᝡ∈ⅈ WBMWJFX$FOUFS WJFXUPQ WJFXCPUUPN WBMWJFX.JEEMFWJFXIFJHIU WBSUFYU:.BUINBY WJFX.JEEMF WJFX$FOUFS GPOU$FOUFS JG QPTJUJPO UPUBM*UFN$PVOU \ WBMOFYU*OJUJBMDBMMCBDLHFU*OJUJBM QPTJUJPO JG OFYU*OJUJBMJOJUJBMWJFX$FOUFSWJFX.JEEMF \ UFYU:WJFX.JEEMFWJFX$FOUFS ^ ^ DESBX5FYU JOJUJBM MBCFM1BEEJOHUP'MPBU UFYU: UFYU1BJOU まず先頭要素の View 中央に Y 座標をとるようにする A ascent descent FontMetrics 原点から 実際の中央への補正 もやっておく
各 initial の先頭要素か画面最上部に張り付くようにラベルが描画される
ItemDecoration を実装する (実際の描画) ラベルを描画すべきと判定した要素について描画位置の Y 座標を決定して c.DrawText() で描画する ᇴ㗖Ә 'POU.FUSJDT
ӘसႠᏍᮏ㮢నՂդԠҵӳᛝӍӐҷӉӊһ㮣 WBMGPOU$FOUFS GPOU.FUSJDTBTDFOU GPOU.FUSJDTEFTDFOU ᇴ㗖Әᝡ∈ⅈ WBMWJFX$FOUFS WJFXUPQ WJFXCPUUPN WBMWJFX.JEEMFWJFXIFJHIU WBSUFYU:.BUINBY WJFX.JEEMF WJFX$FOUFS GPOU$FOUFS JG QPTJUJPO UPUBM*UFN$PVOU \ WBMOFYU*OJUJBMDBMMCBDLHFU*OJUJBM QPTJUJPO JG OFYU*OJUJBMJOJUJBMWJFX$FOUFSWJFX.JEEMF \ UFYU:WJFX.JEEMFWJFX$FOUFS ^ ^ DESBX5FYU JOJUJBM MBCFM1BEEJOHUP'MPBU UFYU: UFYU1BJOU 次の initial が迫ってきたらラベル を上に逃がすように view の中央が 上にずれた分だけ補正する
次の initial の要素が来ると画面外に押し出されるアニメーションが実現できる
最後に 実は DroidKaigi 公式アプリでは座標計算が適当だったので修正しました ↓一応コードが通しで見れるサンプルはこちら↓ https://github.com/e10dokup/StickyHeaderSample 簡単な算数が必要だが場合分けさえしっかり考えれば実現は楽 スピーカー一覧画面をよーく見るとラベルが中央からずれているはず