Slide 1

Slide 1 text

複数のScrollViewが連動! STORES レジ で スプレッドシート風UIを実装しました satoryo

Slide 2

Slide 2 text

自己紹介 2 satoryo X (Twitter) : satoryo056 STORES レジ・予約 iOS / Android エンジニア

Slide 3

Slide 3 text

3 普段 iOS アプリの開発を やっているひと?✋

Slide 4

Slide 4 text

4 iOS アプリ開発について 分かりやすく発表します!

Slide 5

Slide 5 text

STORES レジ について 5 ● 2021年リリースの iPadOS 専用アプリ ● 実店舗とネットショップが一緒になったPOSレジ ○ 商品・在庫・売上管理が可能 
 ● 小売業・サービス業の現地でのお会計に利用

Slide 6

Slide 6 text

STORES 予約 について ● 予約や顧客情報の管理を行うプロダクト ● サロンやフィットネスなどのオーナーさんが利用 ● 例えば以下のことが可能 ○ 予約ページの作成 
 ○ スケジュール管理 
 ○ スタッフのシフト管理 


Slide 7

Slide 7 text

STORES レジ x STORES 予約 7

Slide 8

Slide 8 text

STORES レジ について 8 ● STORES 予約 の予約システムと STORES レジ が連携 ● アプリで予約内容の確認からお会計まで可能に

Slide 9

Slide 9 text

9 今回のメインテーマ 予約カレンダーをネイティブで実装したことについて紹介

Slide 10

Slide 10 text

iOS アプリの開発言語 10 ● ネイティブアプリ ○ Swift
 ○ Objective-C
 ● クロスプラットフォームアプリ ○ JavaScript (React Native)
 ○ Dart (Flutter)
 ○ Kotlin (Kotlin Multiplatform)


Slide 11

Slide 11 text

iOS アプリの開発言語 11 ● ネイティブアプリ ○ Swift
 ○ Objective-C
 ● クロスプラットフォームアプリ ○ JavaScript (React Native)
 ○ Dart (Flutter)
 ○ Kotlin (Kotlin Multiplatform)
 STORES レジは全て Swift で記述

Slide 12

Slide 12 text

iOS アプリの UI フレームワークと実装方法 12 ● UIKit ○ コード
 ○ XIB (XML Interface Builder)
 ○ Storyboard
 ● SwiftUI ○ コード


Slide 13

Slide 13 text

iOS アプリの UI フレームワークと実装方法 13 ● UIKit ○ コード
 ○ XIB (XML Interface Builder)
 ○ Storyboard
 ● SwiftUI ○ コード
 STORES レジでは一部を除いて 全て SwiftUI で UI 実装

Slide 14

Slide 14 text

STORES レジ アプリの採用言語・UIフレームワーク 14 ● 言語 ○ Swift
 ● UI フレームワーク ○ SwiftUI (一部除く) 


Slide 15

Slide 15 text

STORES レジ アプリの採用言語・UIフレームワーク 15 ● 言語 ○ Swift
 ● UI フレームワーク ○ SwiftUI (一部除く) 
 予約カレンダーもSwiftUIで実装したい! まずは関連ライブラリを調査

Slide 16

Slide 16 text

カレンダー実装における関連ライブラリ 16 SpreadsheetView by bannzai 引用元:https://github.com/bannzai/SpreadsheetView


Slide 17

Slide 17 text

カレンダー実装における関連ライブラリ 17 SpreadsheetView by bannzai 引用元:https://github.com/bannzai/SpreadsheetView
 SwiftUI ではなく UIKit で実装

Slide 18

Slide 18 text

カレンダー実装における関連ライブラリ 18 CalendarLib by jumartin 引用元:https://github.com/jumartin/Calendar


Slide 19

Slide 19 text

カレンダー実装における関連ライブラリ 19 CalendarLib by jumartin 引用元:https://github.com/jumartin/Calendar
 そもそも Swift ではなく Objective-C で書かれている

Slide 20

Slide 20 text

カレンダー実装における関連ライブラリ 20 SwiftUI で実装している ライブラリがなさそう ならば作るしかない!

Slide 21

Slide 21 text

予約カレンダーのデザイン 21

Slide 22

Slide 22 text

予約カレンダーの要素 22 ● 3つの要素

Slide 23

Slide 23 text

予約カレンダーの要素 23 ● 3つの要素 ○ スタッフ


Slide 24

Slide 24 text

予約カレンダーの要素 24 ● 3つの要素 ○ スタッフ
 ○ タイムライン 


Slide 25

Slide 25 text

予約カレンダーの要素 25 ● 3つの要素 ○ スタッフ
 ○ タイムライン 
 ○ 予約情報


Slide 26

Slide 26 text

予約カレンダーの要素 26 ● 3つの要素 ○ スタッフ
 ○ タイムライン 
 ○ 予約情報
 1日の予約情報を表示 縦・横方向の スクロールができる画面

Slide 27

Slide 27 text

予約カレンダーの要素 27 何かに似てませんか?

Slide 28

Slide 28 text

予約カレンダーの要素 28 スプレッドシート に似てませんか?

Slide 29

Slide 29 text

予約カレンダーの要素 29 似てますよね?

Slide 30

Slide 30 text

予約カレンダーの要素 30 そう、似てるんですよ

Slide 31

Slide 31 text

伏線回収したので改めて 31

Slide 32

Slide 32 text

予約カレンダーの実装:仕様 32 ● 先頭列(縦)に「スタッフ」を表示 ● 先頭行(横)に「タイムライン 0:00〜24:00」を表示 ● 先頭行・先頭列はそれぞれ固定 ● スタッフとタイムラインの位置に合わせて予約情報を表示 ● カレンダーはスタッフ人数に関係なく画面いっぱいに表示 ○ 人数が少なくてもカレンダーの高さは不変 
 ● 縦にも横にもスクロール可能

Slide 33

Slide 33 text

予約カレンダーの実装:試行錯誤 33 ● ScrollView ● GridView

Slide 34

Slide 34 text

予約カレンダーの実装:試行錯誤 34 予約情報の部分が画面中央に寄ってしまったり

Slide 35

Slide 35 text

予約カレンダーの実装:試行錯誤 35 予約情報の部分が画面中央に寄ってしまったり 余白がある

Slide 36

Slide 36 text

予約カレンダーの実装:試行錯誤 36 タイムラインの部分が画面の外に出てしまったり

Slide 37

Slide 37 text

予約カレンダーの実装:試行錯誤 37 タイムラインの部分が画面の外に出てしまったり 下へ引っ張ると

Slide 38

Slide 38 text

予約カレンダーの実装:試行錯誤 38 タイムラインの部分が画面の外に出てしまったり 下へ引っ張ると タイムラインの部分が出てくる

Slide 39

Slide 39 text

予約カレンダーの実装:試行錯誤 39 タイムラインと予約情報のセルがずれてしまったり

Slide 40

Slide 40 text

予約カレンダーの実装:試行錯誤 40 タイムラインと予約情報のセルがずれてしまったり ずれている ずれている

Slide 41

Slide 41 text

予約カレンダーの実装:試行錯誤 41 ● 改善できないか試行錯誤 ○ ScrollView の中に Spacer を追加
 ○ View の frame を定義
 ○ GeometryReader を使用
 ○ LazyVStack と GridLayout を駆使
 ○ etc …


Slide 42

Slide 42 text

予約カレンダーの実装:試行錯誤 42 ● 改善できないか試行錯誤 ○ ScrollView の中に Spacer を追加
 ○ View の frame を定義
 ○ GeometryReader を使用
 ○ LazyVStack と GridLayout を駆使
 ○ etc …
 改善の兆しは見えず

Slide 43

Slide 43 text

予約カレンダーの実装:気づき 43

Slide 44

Slide 44 text

予約カレンダーの実装:気づき 44 ● 3つの要素 ○ スタッフ
 ○ タイムライン 
 ○ 予約情報


Slide 45

Slide 45 text

予約カレンダーの実装:気づき 45 1. 縦にスクロールする場合 ・スタッフをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  スタッフも一緒にスクロール  

Slide 46

Slide 46 text

予約カレンダーの実装:気づき 46 1. 縦にスクロールする場合 ・スタッフをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  スタッフも一緒にスクロール  

Slide 47

Slide 47 text

予約カレンダーの実装:気づき 47 1. 縦にスクロールする場合 ・スタッフをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  スタッフも一緒にスクロール  

Slide 48

Slide 48 text

予約カレンダーの実装:気づき 48 1. 縦にスクロールする場合 ・スタッフをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  スタッフも一緒にスクロール  

Slide 49

Slide 49 text

予約カレンダーの実装:気づき 49 1. 縦にスクロールする場合 ・スタッフをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  スタッフも一緒にスクロール  

Slide 50

Slide 50 text

予約カレンダーの実装:気づき 50 2. 横にスクロールする場合 ・タイムラインをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  タイムラインも一緒にスクロール

Slide 51

Slide 51 text

予約カレンダーの実装:気づき 51 2. 横にスクロールする場合 ・タイムラインをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  タイムラインも一緒にスクロール

Slide 52

Slide 52 text

予約カレンダーの実装:気づき 52 2. 横にスクロールする場合 ・タイムラインをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  タイムラインも一緒にスクロール

Slide 53

Slide 53 text

予約カレンダーの実装:気づき 53 2. 横にスクロールする場合 ・タイムラインをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  タイムラインも一緒にスクロール

Slide 54

Slide 54 text

予約カレンダーの実装:気づき 54 2. 横にスクロールする場合 ・タイムラインをスクロールしたら  予約情報も一緒にスクロール ・予約情報をスクロールしたら  タイムラインも一緒にスクロール

Slide 55

Slide 55 text

予約カレンダーの実装:気づき 55 縦にスクロール ・スタッフ & 予約情報 横にスクロール ・タイムライン & 予約情報 片方がスクロールしたら もう片方も連動させたい!

Slide 56

Slide 56 text

予約カレンダーの実装:気づき 56 縦にスクロール ・スタッフ & 予約情報 横にスクロール ・タイムライン & 予約情報 片方がスクロールしたら もう片方も連動させたい!

Slide 57

Slide 57 text

予約カレンダーの実装:気づき 57 縦にスクロール ・スタッフ & 予約情報 横にスクロール ・タイムライン & 予約情報 片方がスクロールしたら もう片方も連動させたい!

Slide 58

Slide 58 text

予約カレンダーの実装:関連実装を発見 58 複数のScrollViewを同時に動かす実装を発見 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 59

Slide 59 text

予約カレンダーの実装:SimultaneouslyScrollView の紹介 59 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 60

Slide 60 text

予約カレンダーの実装:SimultaneouslyScrollView の紹介 60 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 61

Slide 61 text

予約カレンダーの実装:SimultaneouslyScrollView の紹介 61 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 62

Slide 62 text

予約カレンダーの実装:SimultaneouslyScrollView の紹介 62 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 真ん中のScrollViewをスクロールすると 左右のScrollViewも連動してスクロールする

Slide 63

Slide 63 text

予約カレンダーの実装:SimultaneouslyScrollView の紹介 63 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 真ん中のScrollViewをスクロールすると 左右のScrollViewも連動してスクロールする なんとなくいけそうな予感!

Slide 64

Slide 64 text

予約カレンダーの実装:SimultaneouslyScrollView のソースコード 64 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 65

Slide 65 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 65 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始


Slide 66

Slide 66 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 66 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向 
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始


Slide 67

Slide 67 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 67 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意 
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始


Slide 68

Slide 68 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 68 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール 
 させる全ての ScrollView を
 配列に格納 
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始


Slide 69

Slide 69 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 69 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意 
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始


Slide 70

Slide 70 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 70 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全てのScrollView を 同じ位置まで自動スクロール
 5. 任意の ScrollView を
 スクロール開始 


Slide 71

Slide 71 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 71 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全ての ScrollView を同じ位置まで自動スクロール 
 5. 任意の ScrollView を
 スクロール開始


Slide 72

Slide 72 text

予約カレンダーの実装:ScrollView のスクロールを検知する仕組み 72 UIScrollViewDelegate を継承した extension を用意 引用元:https://github.com/stonko1994/SimultaneouslyScrollView


Slide 73

Slide 73 text

予約カレンダーの実装:ScrollView のスクロールを検知する仕組み 73 UIScrollViewDelegate を継承した extension を用意 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 スクロール開始時 に呼ばれる

Slide 74

Slide 74 text

予約カレンダーの実装:ScrollView のスクロールを検知する仕組み 74 7. UIScrollViewDelegate を継承した extension を定義 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 スクロール中に 呼ばれる

Slide 75

Slide 75 text

予約カレンダーの実装:ScrollView のスクロールを検知する仕組み 75 UIScrollViewDelegate を継承した extension を定義 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 操作中の ScrollView を代入 操作中でない配列内の 全ての ScrollView を スクロールさせる

Slide 76

Slide 76 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 76 ● 3つの要素 ○ スタッフ
 ○ タイムライン 
 ○ 予約情報


Slide 77

Slide 77 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 77

Slide 78

Slide 78 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 78

Slide 79

Slide 79 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 79 ス タ ッ フ タイムライン 予約情報 横に並べる

Slide 80

Slide 80 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 80 ス タ ッ フ タイムライン 予約情報 縦に並べる

Slide 81

Slide 81 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 81

Slide 82

Slide 82 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 82

Slide 83

Slide 83 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 83

Slide 84

Slide 84 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 84

Slide 85

Slide 85 text

予約カレンダーの実装:SimultaneouslyScrollView を反映 85

Slide 86

Slide 86 text

予約カレンダーの実装:SimultaneouslyScrollView の処理フロー 86 引用元:https://github.com/stonko1994/SimultaneouslyScrollView
 2. ScrollViewの配列を用意
 3. 同じ方向にスクロール
 させる全てのScrollView を
 配列に格納
 1. スクロールする方向
 (縦 or 横) を決定
 4. ScrollView のスクロールを 検知する仕組みを用意
 6. 配列内の全ての ScrollView を同じ位置まで自動スクロール 
 5. 任意の ScrollView を
 スクロール開始


Slide 87

Slide 87 text

完成! 87

Slide 88

Slide 88 text

余談:予約の表示 88 予約情報の考慮事項

Slide 89

Slide 89 text

余談:予約の表示 89 予約情報の考慮事項 ● 開始時間 ○ 00分・30分・45分開始...
 ● 予約の長さ ○ 1時間・30分・2.5時間...
 ● 予約の重複 ○ スタッフと予約は 1 対 多


Slide 90

Slide 90 text

余談:予約の表示 90 予約情報の考慮事項 ● 開始時間 ○ タイムラインの位置を考慮 
 ● 予約の長さ ○ 予約ごとに描画の幅が可変 
 ● 予約の重複 ○ スタッフの高さも可変 


Slide 91

Slide 91 text

余談:予約の表示 91 予約情報の考慮事項  APIで取得した予約情報を  スタッフごとに抽出し  予約同士で時間の重複を判定し  スタッフの高さを変えつつ  予約のセルの幅を変えながら  1つずつ描画する

Slide 92

Slide 92 text

余談:予約の表示 92 2つの ForEach を使用し予約を1つずつ描画

Slide 93

Slide 93 text

余談:予約の表示 93 2つの ForEach を使用し予約を1つずつ描画

Slide 94

Slide 94 text

改めて、完成! 94

Slide 95

Slide 95 text

改めて、完成! 95

Slide 96

Slide 96 text

予約カレンダーの課題・改善点 96 ● パフォーマンス面 ○ 予約数が増えるほど描画する予約情報も増加 
 ○ 大量の予約を描画するとスクロールがカクつく 
 ● UI 操作 ○ ドラッグ&ドロップで時間を変更したいという要望 
 ■ 予約ごとに座標を指定しているのが課題 


Slide 97

Slide 97 text

まとめ 97 ● STORES レジ アプリの予約カレンダーを紹介 ● 複数のScrollViewを同時に動かすロジックにより   スプレッドシート風なUIを実装 ● まだまだ課題はあるが今後改善する予定

Slide 98

Slide 98 text

さいごに:STORES 各サービスの連携デモ 98 予約カレンダーも触れるのでぜひ体験してください!