Swift4 Day92:APP 製作從0到1全記錄(上)

Swift4 / iOS11 / 2018.12.03/ Moving

Alice
Daily Swift
10 min readDec 3, 2018

--

介紹

幸運的加入了 AppWorks School 之後,經歷一連串學習 iOS 的基礎知識之後,開始了我的第二個個人專案:Moving健身運動教練

一開始要做自己的專案時,想了很久也不知道要做什麼,而且只有五週就要完成上架的時程壓力。

更重要的是個人專案作品的好壞,會影響到你最後能收到多少面試機會。

最後就從自己的生活中下手,想改善自己用 Youtube 健身的一些問題

  • 希望能跳過解說專注在運動的部分
  • 解決影片秒數與目標運動長度不同的問題
  • 無法紀錄運動時間

決定好大方向想要做的 App 之後,要開始調查怎麼實作,因為很多想出來的功能其實自己也沒實作過,還有研究類似的 App 截長補短,把基本的 UI 跟想做的功能做成簡報,跟 AppWorks School 的大家簡報介紹自己要做的內容。那時候的介紹功能簡報長這樣跟現在實際成品差很多 😂

接著我們會用 Trello 去把要做的事情拆成小的功能,將要做的是排在不同的類別裡。每天早上開早會的時候,就會跟 iOS 班的大家討論,自己昨天做了什麼、今天要做什麼,有問題的話也可以在這時候提出來問我們的 Mentor Luke 大大討論。

在 Trello 上會有下列幾種分類方式:

Product Backlog:一開始所有要做的事,突然想要做的功能就放進去。

Sprint Backlog:其實看到 announcement 裡,都有紀錄每個 Sprint 的時間段,所以自己決定這個 Sprint 要做的事就會放進 Sprint Backlog裡。

Todo:會把這一兩天想做的事放在 Todo。

Doing:正在做的部分就會把卡移到這裡。

Done:做完的時候就會把自己的卡移到這。

Youtube Player 建置

一開始我最主要的功能是希望能播放 Youtube 、暫停 Youtube、切換 Youtube 的時間,所以我先去調查,怎麼樣做出類似的功能。所以我用了 YouTubePlayer-Swift 這個 framework 。

我作出了可以播放、暫停、切換影片的雛形,我就把它應用在我的 project 中了,但我後來才發現他有很多問題與限制是一開始難以發現的,像你放大影片 切回來 StatusBar 會消失、拉時間條無法偵測、狂按播放暫停會 crash、而且上方的 Youtube 頻道的名稱按下去會導到 Youtube 之類的問題。

後來我就讓videoView.isUserInteractionEnabled = false

用點擊Cell的方式去改變影片的狀態。

這個framework只有7顆星星,換成他 fork 的原始檔也是有相同問題。QQ

APP 資料結構設計與存取

點選第一頁運動頁面,就要去抓出所有這個運動部位的運動計劃,切換到第二個頁面 ListModel 中應該要有一個 ActionModel 的 Array ,存這個運動計畫的各個動作與動作的狀態。

一開始我只用一個名為 LocaolDatabase 的 class ,裝著所有本地端資料結構,大概像這樣,用 Singleton 方式設計。

這才只是兩個動作 / Reachability 判斷網路行為

即使沒有網路也可以看到運動內容與圖片,只是播放影片的時候會用 Reachability 去判斷網路行為,處理沒有網路時內容呈現。

BUT!

有一天發現其中一支影片不能連接了,我更新好之後卻要等 Apple 審核,覺得這樣太慢了,我就決定把我的 LocaolDatabase 的資料搬到 Firebase。

Struct 轉 JSON

首先將資料Encode,然後將 console 的內容複製到 Sublime ,把副檔名改成 JSON,或直接用 Swift File也能做 JSON 檔。在 Firebase選擇匯入 JSON 就不用重新輸入資料了。原本不知道還差點要手打勒 QQ

在每一個運動計畫加上 Category ,回到本地端 Filter 就能分好所有運動種類。

網路存取圖片

因為所有資料都透過 Firebase 傳遞,所以我將圖片存在 Firebase Storage後,再將 URL 存回 Firebase Database ,到本地的時候用 Kingfisher 套件解析圖片,也要處理更新前的圖片讀取的方法。

動畫介紹

看到這一頁先拆解一下要做的事吧

  • 要辨別運動時間與休息時間,處理不同動畫,要能暫停
  • 處理 tableview 的 reuse 機制,因為設計上動畫條是不在 model 上的
  • 點選 cell 的時候,判斷現在 cell 與被點選的 cell 的關係,切換影片時切換也要處理其他所有 cell 的狀態
  • 處理影片時間與目標影片時間不同
  • 換動作的時候, 運動的cell 對齊影片,但當你按最後一個 cell 時該怎麼做

再來一個一個介紹🙋‍

要辨別運動時間與休息時間,處理不同動畫,要能暫停

大家想要更了解動畫可以參考,我們家志瑋的簡報。

同場加映:我們家智瑋在 iPlayground 的演講:https://goo.gl/pttzLb

簡單來說對我需求而言,就是 大家平常使用的 Core Animtion 沒有辦法暫停,只能執行與移除。在動畫一開始時,其實你的物件就在目標處了,眼睛所看到的動畫,都是假的,是 Presentation Layer 幫你畫的,所以你想知道現在畫面長到哪,要檢查的是 Presentation Layer。

後來我選擇用 UIViewPropertyAnimatior 做我的專案,可以暫停與 restart 。

要辨別運動時間與休息時間,其實把 property 寫在 ActionModel 裡,修改後讓 View 與 Model 維持一致就好。

處理 tableview 的 reuse 機制,因為設計上動畫條是不在 model 上的

我寫的 function actionViewWidthAnimate 中判斷兩個狀況,目前運動秒數與初始秒數相同,就從頭畫動畫。
如果有被 reuse,就在 willDisplay cell 的地方傳 UITableViewCell 回 actionViewWidthAnimate 去重畫,抓到現在的秒數與總時間的比例,讓他長到該在的地方,然後繼續長好長滿。 rest 也是用相同的方法做處理。

點選 cell 的時候,判斷現在 cell 與被點選的 cell 的關係,切換影片時切換也要處理其他所有 cell 的狀態

在 didSelectRowAt 中判斷,點選的 cell 是否是正在運動的 cell ,是的話就暫停或播放,不是的話就去判斷他們關係,還有相對應的畫面呈現。

處理影片時間與目標秒數不同的關係

我用 asyncAfter 讓現在的時間加上該 repeat 的秒數,如果時間到了還是在相同的影片,就會 seekTo 他原先的影片位置。

換動作的時候, 運動的cell 對齊影片,但當你按最後一個 cell 時該怎麼做

tableview 會不夠長,對吧?那就用 contentInset 讓他變長吧。

最長只要達到, TableView 全長減一個 cell 的高,雖然也可以用 row 距離底部多長去做變化,但我就直接讓他長最長啦。

這個專案的 GitHub :

下集在這👉

--

--