今天就來做收支記錄界面的收尾,預計會把收、支記錄以顏色區分,並透過日期分組,最後再加上一點統計資料。
在「快速記帳」中的每個記錄的背景都是黑色的,而在收支記錄中,預計會用綠色顯示收入,紅色顯示支出,如下:
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
}
}
如此一來,就能把系統騙得不要不要的。
除了讓每筆資料都能有漂亮的綠色、紅色,我還想以日期區分記錄,並顯示每天總共收、支多少錢。
在 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)
首先我們要先建立一個客製化的 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
程式碼隨著時間的推移,又越來越髒了,果然沒有了同事這種生物的時候,人就會開始墮落。
你以為下一篇又要整理程式碼嗎?哦不,太天真了,功能沒有出來之前,老闆是不會讓你休息的。
還有很多功能要生出來,下一篇預計會開始加入統計、圖表相關功能。
備註:其實後來發現快速記帳、收支記錄應該合在一起,使用者在新增時預設為快速記帳,但是多給一個按鈕讓使用者展開填更多。