iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
1
Software Development

iOS 三十天上架記帳 APP系列 第 20

Money Mom - 實做收支記錄的界面 Part ∞

  • 分享至 

  • xImage
  •  

今天就來做收支記錄界面的收尾,預計會把收、支記錄以顏色區分,並透過日期分組,最後再加上一點統計資料。

依照收支改變顏色

在「快速記帳」中的每個記錄的背景都是黑色的,而在收支記錄中,預計會用綠色顯示收入,紅色顯示支出,如下:

if transaction.type == .INCOME {
    amountLabel.textColor = MMColor.black
    amountLabel.backgroundColor = MMColor.green
    playButton.setTitleColor(MMColor.black, for: .normal)
    playButton.backgroundColor = MMColor.green
} else {
    amountLabel.textColor = MMColor.white
    amountLabel.backgroundColor = MMColor.red
    playButton.setTitleColor(MMColor.white, for: .normal)
    playButton.backgroundColor = MMColor.red
}

此時我們會面臨一個問題,就是界面怎麽跑都是紅色的,原因是因為我們「偽裝」的 TransactinoType,沒有加入 == 的功能,系統不知道該怎麼比較兩者是否「相等」,我們可以再來幫 TransactionType 補上:

extension TransactionType {
    static func ==(lhs: TransactionType, rhs: TransactionType) -> Bool {
        return lhs.rawValue == rhs.rawValue
    }
}

如此一來,就能把系統騙得不要不要的。

客製化 UITableViewHeaderFooterView

除了讓每筆資料都能有漂亮的綠色、紅色,我還想以日期區分記錄,並顯示每天總共收、支多少錢。

以日期分組

在 Core Data 中每筆收支記錄都有日期,但我們不能直接用這個日期欄位來做分組,因為該欄位還同時包含時間,而我們只需要「年、月、日」,因此我們可以在 Transaction 中新增一個屬性,把日期欄位轉換成我們需要的格式,再請 NSFetchedResultsController 使用我們指定的屬性分組,如下:

@objc var createdAtDay: String {
    get {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .none
        formatter.timeZone = TimeZone.current
        return formatter.string(from: createdAt)
    }
}
let fetchedResultsController = NSFetchedResultsController<Transaction>(fetchRequest: request, managedObjectContext: viewContext, sectionNameKeyPath: #keyPath(Transaction.createdAtDay), cacheName: nil)

設定 UITableView 使用客製化的 Header

首先我們要先建立一個客製化的 UITableViewHeaderFooterView,如下:

class TransactionTableHeaderView: UITableViewHeaderFooterView {
}

接著再設定 UITableView 使用這個客製化的 Header,如下:

register(TransactionTableHeaderView.self, forHeaderFooterViewReuseIdentifier: NSStringFromClass(TransactionTableHeaderView.self))

接著我們就可以新增一些我們需要的資料,如下:

class TransactionTableHeaderView: UITableViewHeaderFooterView {
    var totalIncome = NSDecimalNumber.zero {
        didSet {
            totalIncomeLabel.text = "收入 \(totalIncome)"
        }
    }

    var totalExpense = NSDecimalNumber.zero {
        didSet {
            totalExpenseLabel.text = "支出 \(totalExpense)"
        }
    }

    var date = Date() {
        didSet {
            let calendar = Calendar.current
            let components = calendar.dateComponents([.year, .month, .day], from: date)

            if let day = components.day {
                dayLabel.text = String(describing: day)
                dayLabel.sizeToFit()
            }

            if let month = components.month, let year = components.year {
                monthYearLabel.text = "/ \(month) / \(year)"
                monthYearLabel.sizeToFit()
            }
        }
    }
}

最後再補上 UITableView 相關的 Delegate 就能完成囉:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    guard let sectionInfo = fetchedResultsController.sections?[section] else {
        return nil
    }

    let headerView = (tableView as! TransactionTableView).dequeueReusableHeaderView()

    var totalIncome = NSDecimalNumber.zero
    var totalExpense = NSDecimalNumber.zero

    sectionInfo.objects?.forEach { transaction in
        guard let transaction = transaction as? Transaction else {
            return
        }

        guard transaction.amount != NSDecimalNumber.notANumber else {
            return
        }

        if transaction.type == .INCOME {
            totalIncome = totalIncome.adding(transaction.amount)
        } else {
            totalExpense = totalExpense.adding(transaction.amount)
        }
    }

    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    formatter.timeStyle = .none
    formatter.timeZone = TimeZone.current

    headerView.date = formatter.date(from: sectionInfo.name) ?? Date()
    headerView.totalIncome = totalIncome
    headerView.totalExpense = totalExpense

    return headerView
}

展示

你以為是 GIF 嗎?抱歉,我懶。

程式碼:GitHub

程式碼隨著時間的推移,又越來越髒了,果然沒有了同事這種生物的時候,人就會開始墮落。

你以為下一篇又要整理程式碼嗎?哦不,太天真了,功能沒有出來之前,老闆是不會讓你休息的。

還有很多功能要生出來,下一篇預計會開始加入統計、圖表相關功能。

備註:其實後來發現快速記帳、收支記錄應該合在一起,使用者在新增時預設為快速記帳,但是多給一個按鈕讓使用者展開填更多。


上一篇
Money Mom - 實做收支記錄的界面 Part 2
下一篇
Money Mom - 統計功能規劃
系列文
iOS 三十天上架記帳 APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
zdey
iT邦新手 5 級 ‧ 2018-01-09 13:56:21

好想看GIF喔

我要留言

立即登入留言