# (Swift) 利用 UIBezierPath 製作記帳 APP
功能展示
- 利用 UIBezierPath 繪製 圓餅圖
- 利用 UIToolbar 製作 記帳新增與扣除按鈕
- 利用 UIAlertController 製作警示視窗
- 利用 prepare() 傳送頁面資料
頁面之間的連線
想要讓記帳頁面呈現的效果為 Page Sheet 的話,必須在 ViewController 之間再插入一個 NavigationController
在我的這篇文章中有實現步驟
製作底層的圓餅圖
let aDegree = CGFloat.pi / 180func creatcirclePath() {
let circlePath = UIBezierPath(arcCenter: view.center, radius: 90, startAngle: aDegree * 270, endAngle: aDegree * (270 + 360), clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor(red: 133/255, green: 92/255, blue: 248/255, alpha: 1).cgColor
circleLayer.lineWidth = 40
view.layer.addSublayer(circleLayer)
}
製作快速移動且能加減的 TextField
如何透過 ToolBar 在 TextField 之間快速移動,能查看這篇文章
而加減的程式也能透過 UIToolBar 新增
// 製作 plus 按鍵
let plusButton = UIBarButtonItem(image: UIImage(systemName: "plus.circle"), style: .plain, target: nil, action: #selector(plusmoney))@objc func plusmoney() {
editaccount.personal += Int(textfieldCollection[0].text!) ?? 0
Labelcollection[0].text = "個人:\(moneyString(editaccount.personal))"
textfieldCollection[0].text = ""
....
其中我定義了一個函數 moneyString() 將輸入數字轉換為 金錢格式
可以參考以下文章實現
func moneyString(_ money: Int) -> String{
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "zh_TW")
formatter.numberStyle = .currency
return formatter.string(from: NSNumber(value: money)) ?? ""
}
製作欄位清除警視窗
為了不誤觸清除按鍵,因此使用 UIAlertController 來製作清除前的警示視窗
let alertController = UIAlertController(title: "是否要刪除本欄累積金額🥺", message: "", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
alertController.addAction(UIAlertAction(title: "Yes", style: .default, handler: { _ in
switch sender {
case self.clearButtonCollection[0]:
self.editaccount.personal = 0
self.Labelcollection[0].text = "個人:\(self.moneyString(self.editaccount.personal))"
self.textfieldCollection[0].text = ""
...
讀取編輯頁面資料
使用 unwind…()讀取編輯頁面的資料
var myasset = Spending(personal: 0, dietary: 0, shopping: 0, traffic: 0, medical: 0, life: 0)
amount 為所有記帳總和
@IBAction func unwindToDone(_ unwindSegue: UIStoryboardSegue) {
// let sourceViewController = unwindSegue.source
if let source = unwindSegue.source as? accountingTableViewController {
myasset = source.editaccount
amount = myasset.life + myasset.medical + myasset.dietary + myasset.shopping + myasset.personal + myasset.traffic
將資料傳回編輯頁面
這邊使用 prepare 必需要注意,要先設定 ViewController 到 NavigationController 的 identifier
設定好 identifier 後,在 ViewController 中的 prepare 輸入以下
程式,輸入後即可將資料傳回編輯頁面
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueShowNavigation01" {
if let destVC = segue.destination as? UINavigationController,
let targetController = destVC.topViewController as? accountingTableViewController {
targetController.editaccount = myasset
}
}
}
繪製記帳頁面中各項金額的比例
我把觸發繪圖的程式寫在 unwind…() 中,這邊我也會搭配上 enumerated(), 作為讀取預設好的 colors 值
for (index, percentage) in percentages.enumerated() { let endDegree = startDegree + (percentage / percentages.reduce(0, +)) * 360
let percentagePath = UIBezierPath(arcCenter: view.center, radius: 90, startAngle: aDegree * startDegree, endAngle: aDegree * endDegree, clockwise: true)
let percentageLayer = CAShapeLayer()
percentageLayer.path = percentagePath.cgPath
percentageLayer.fillColor = UIColor.clear.cgColor
percentageLayer.lineWidth = 40
percentageLayer.strokeColor = colors[index]
view.layer.addSublayer(percentageLayer)
percentageLayers.append(percentageLayer)
startDegree = endDegree
還有預先設定好一個 percentages , 來方便使用 reduce(0, +) 取得總金額
最關鍵的 endDegree 表示方式,總金額中的其中一項消費,我採用計算的方式是 某 項消費 /總金額 再乘上 360
let endDegree = startDegree + (percentage / percentages.reduce(0, +)) * 360
細節繪圖可以參考這篇
避免繪圖沒有被清除
在每次編輯預算後傳回資料頁面,其實就是利用新的 圖層疊上去,所以為了避免以上狀況,必須在新增新的圖層前,將舊圖層清除乾淨
// 刪除 所有perentageLayers
for deleteLayer in percentageLayers{
deleteLayer.removeFromSuperlayer()
}
percentageLayers.removeAll()
詳細操作可以參考這篇
修正後
記帳 APP 可沒這麼簡單,必須花更多的時間慢慢修改及增加新功能,年初錄取研究所後,就比較少碰 Swift,但我還是很喜歡開發 APP ,所以我會繼續堅持下去,期待能做出更好的 APP。