# (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 必需要注意,要先設定 ViewControllerNavigationControlleridentifier

設定好 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。

GitHub

--

--