Slide 1

Slide 1 text

Kotlin + DataBinding を使った RecyclerView の実装 第3 回Kotlin 勉強会 @ Sansan @jumpersons

Slide 2

Slide 2 text

自己紹介 株式会社カカクコム でアプリエンジニア 以前はWeb エンジニア(.NET) 2015 年5 月よりiOS エンジニア 2016 年5 月よりAndroid エンジニア

Slide 3

Slide 3 text

最初に教えてもらったこと ListView よりRecyclerView がいいよ。 DataBinding が便利だからMVVM がいいよ。

Slide 4

Slide 4 text

Kotlin 良い RecyclerView + DataBinding で実装したら Kotlin で書いて良かったと思えた。 (Java だと辛そう。。。) Kotlin でどのように実装し、 どのように良かったご紹介。

Slide 5

Slide 5 text

こういう画面求められませんか? リスト表示だけどView が微妙に違う。

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

実装の方針 View のレイアウトはそれぞれ定義 ReyclerView を使う デー タはフラットに持つ

Slide 8

Slide 8 text

View のレイアウトはそれぞれ定義

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

デー タはこのような構造で持つ s e a l e d c l a s s L i s t I t e m { a b s t r a c t f u n g e t T y p e ( ) : T y p e e n u m c l a s s T y p e ( v a l i d : I n t ) { C a p t i o n ( 1 0 ) , S u b C a p t i o n ( 2 0 ) , C a t e g o r y ( 3 0 ) ; c o m p a n i o n o b j e c t { f u n f r o m ( i d : I n t ) : T y p e { r e t u r n v a l u e s ( ) . f i r s t { i t . i d = = i d } } } } c l a s s C a p t i o n I t e m ( v a l t i t l e : S t r i n g ) : L i s t I t e m ( ) { o v e r r i d e f u n g e t T y p e ( ) : T y p e { r e t u r n T y p e . C a p t i o n } } c l a s s S u b C a p t i o n I t e m ( v a l t i t l e : S t r i n g ) : L i s t I t e m ( ) {

Slide 11

Slide 11 text

RecyclerViewAdapter 主要なメソッド デー タの数を返す View の種類をInt で返す ViewHolder を返す(postion: Int がない) View にデー タをバインドする f u n g e t I t e m C o u n t ( ) f u n g e t I t e m V i e w T y p e ( p o s i t i o n : I n t ) : I n t f u n o n C r e a t e V i e w H o l d e r ( p a r e n t : V i e w G r o u p ? , v i e w T y p e : I n t ) : R e c y c l e r V i e w . V f u n o n B i n d V i e w H o l d e r ( h o l d e r : R e c y c l e r V i e w . V i e w H o l d e r ? , p o s i t i o n : I n t )

Slide 12

Slide 12 text

RecyclerViewAdapter 実装 constructor sealed class のList でデー タを持つ c l a s s C a t e g o r y L i s t R e c y c l e r V i e w A d a p t e r ( p r i v a t e v a r i t e m s : L i s t < C a t e g o r y L i s t V i e w M o d e l . L i s t I t e m > ) : R e c y c l e r V i e w . A d a p t e r < R e c y c l e r V i e w . V i e w H o l d e r > ( ) { }

Slide 13

Slide 13 text

RecyclerViewAdapter 実装 fun getItemCount フラットなリストで持っているので返すだけ o v e r r i d e f u n g e t I t e m C o u n t ( ) = i t e m s . c o u n t ( )

Slide 14

Slide 14 text

RecyclerViewAdapter 実装 fun getItemViewType enum のid を返す o v e r r i d e f u n g e t I t e m V i e w T y p e ( p o s i t i o n : I n t ) : I n t { v a l i t e m = i t e m s [ p o s i t i o n ] r e t u r n i t e m . g e t T y p e ( ) . i d }

Slide 15

Slide 15 text

RecyclerViewAdapter 実装 fun onCreateViewHolder enum 毎にViewHolder を返す o v e r r i d e f u n o n C r e a t e V i e w H o l d e r ( p a r e n t : V i e w G r o u p ? , v i e w T y p e : I n t ) : R e c y c l e r V p a r e n t ? : r e t u r n n u l l v a l i t e m T y p e = C a t e g o r y L i s t V i e w M o d e l . L i s t I t e m . T y p e . f r o m ( v i e w T y p e ) w h e n ( i t e m T y p e ) { C a t e g o r y L i s t V i e w M o d e l . L i s t I t e m . T y p e . C a p t i o n - > { v a l b i n d i n g = C a p t i o n I t e m B i n d i n g . i n f l a t e ( L a y o u t I n f l a t e r . f r o m ( r e t u r n C a p t i o n I t e m V i e w H o l d e r ( b i n d i n g ) } C a t e g o r y L i s t V i e w M o d e l . L i s t I t e m . T y p e . S u b C a p t i o n - > { v a l b i n d i n g = S u b C a p t i o n I t e m B i n d i n g . i n f l a t e ( L a y o u t I n f l a t e r . f r r e t u r n S u b C a p t i o n I t e m V i e w H o l d e r ( b i n d i n g ) } C a t e g o r y L i s t V i e w M o d e l . L i s t I t e m . T y p e . C a t e g o r y - > { v a l b i n d i n g = C a t e g o r y I t e m B i n d i n g . i n f l a t e ( L a y o u t I n f l a t e r . f r o m

Slide 16

Slide 16 text

RecyclerViewAdapter 実装 ViewHolder はこんな感じ p r i v a t e c l a s s C a p t i o n I t e m V i e w H o l d e r ( v a l b i n d i n g : C a p t i o n I t e m B i n d i n g ) : R e c y c l e r V i e w . V i e w H o l d e r ( b i n d i n g . r o o t ) { } p r i v a t e c l a s s S u b C a p t i o n I t e m V i e w H o l d e r ( v a l b i n d i n g : S u b C a p t i o n I t e m B i n d i n g ) : R e c y c l e r V i e w . V i e w H o l d e r ( b i n d i n g . r o o t ) { } p r i v a t e c l a s s C a t e g o r y I t e m V i e w H o l d e r ( v a l b i n d i n g : C a t e g o r y I t e m B i n d i n g ) : R e c y c l e r V i e w . V i e w H o l d e r ( b i n d i n g . r o o t ) { }

Slide 17

Slide 17 text

RecyclerViewAdapter 実装 fun onBindViewHolder ViewHolder とデー タをCast してデー タをバインド o v e r r i d e f u n o n B i n d V i e w H o l d e r ( h o l d e r : R e c y c l e r V i e w . V i e w H o l d e r ? , p o s i t i o n : I n t v a l i t e m = i t e m s [ p o s i t i o n ] w h e n { h o l d e r i s C a p t i o n I t e m V i e w H o l d e r & & i t e m i s C a t e g o r y L i s t V i e w M o d e l . @ S u p p r e s s ( " M I S S I N G _ D E P E N D E N C Y _ C L A S S " ) h o l d e r . b i n d i n g . i t e m = i t e m } h o l d e r i s S u b C a p t i o n I t e m V i e w H o l d e r & & i t e m i s C a t e g o r y L i s t V i e w M o d @ S u p p r e s s ( " M I S S I N G _ D E P E N D E N C Y _ C L A S S " ) h o l d e r . b i n d i n g . i t e m = i t e m } h o l d e r i s C a t e g o r y I t e m V i e w H o l d e r & & i t e m i s C a t e g o r y L i s t V i e w M o d e l @ S u p p r e s s ( " M I S S I N G _ D E P E N D E N C Y _ C L A S S " )

Slide 18

Slide 18 text

良かったところ ViewType のInt の管理がsealed class の宣言のところでま とめられ見通しが良い View の種類が増える場合はパター ンマッチの網羅チェ ックがかかる RecyclerView の作り上Cast は仕方ないがKotlin はCast が 優秀なので実装しやすい

Slide 19

Slide 19 text

残念だったところ enum で一意の値を持てない onBindViewHolder でViewHolder とデー タのキャストが 必要で網羅チェックができない ViewHolder の判定にViewType:Int は辛い

Slide 20

Slide 20 text

ご静聴ありがとうございました。 https://github.com/jumperson/Kotlin-sansan-20160701