
Spending Tracker
by dockui
Track your expenses effortlessly with this intuitive template. Simple, sleek design to help users monitor their finances with ease. Perfect for budgeting apps!
- Platform
- SwiftUI
- Code
- Native Swift
- Format
- Screen
- Access
- Free
Code Snippet
import SwiftUI
import Charts
struct Transaction: Identifiable {
let id = UUID()
let title: String
let amount: Double
let category: TransactionCategory
let date: Date
let isIncome: Bool
}
struct FinancialMetric: Identifiable {
let id = UUID()
let title: String
let value: Double
let trend: Double // Percentage change
let icon: String
let color: Color
}
enum TransactionCategory: String {
case food = "Food & Dining"
case shopping = "Shopping"
case transport = "Transport"
case utilities = "Utilities"
case entertainment = "Entertainment"
case income = "Income"
var icon: String {
switch self {
case .food: "fork.knife"
case .shopping: "cart.fill"
case .transport: "car.fill"
case .utilities: "bolt.fill"
case .entertainment: "tv.fill"
case .income: "dollarsign.circle.fill"
}
}
var color: Color {
switch self {
case .food: .orange
case .shopping: .blue
case .transport: .green
case .utilities: .purple
case .entertainment: .pink
case .income: .mint
}
}
}
struct BalanceHistory: Identifiable {
let id = UUID()
let date: Date
let balance: Double
}
struct FinanceDashboardView: View {
// Dummy Data
let metrics = [
FinancialMetric(title: "Total Balance", value: 12450.80, trend: 2.5, icon: "dollarsign.circle.fill", color: .blue),
FinancialMetric(title: "Income", value: 4500.00, trend: 5.2, icon: "arrow.down.circle.fill", color: .green),
FinancialMetric(title: "Expenses", value: 2300.50, trend: -1.8, icon: "arrow.up.circle.fill", color: .red)
]
let transactions = [
Transaction(title: "Grocery Store", amount: 85.50, category: .food, date: Date(), isIncome: false),
Transaction(title: "Salary Deposit", amount: 4500.00, category: .income, date: Date().addingTimeInterval(-86400), isIncome: true),
Transaction(title: "Netflix", amount: 15.99, category: .entertainment, date: Date().addingTimeInterval(-172800), isIncome: false),
Transaction(title: "Uber Ride", amount: 24.50, category: .transport, date: Date().addingTimeInterval(-259200), isIncome: false)
]
let monthlySpending: [(category: TransactionCategory, amount: Double)] = [
(.food, 450.0),
(.shopping, 320.0),
(.transport, 180.0),
(.utilities, 250.0),
(.entertainment, 150.0)
]
let balanceHistory: [BalanceHistory] = (0..<7).map { days in
BalanceHistory(
date: Date().addingTimeInterval(-Double(days) * 86400),
balance: Double.random(in: 10000...13000)
)
}
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: 24) {
metricsGrid
balanceChart
spendingBreakdown
recentTransactions
}
.padding()
}
.navigationTitle("Finance")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(action: {}) {
Image(systemName: "bell.badge")
.symbolRenderingMode(.multicolor)
.font(.title3)
}
}
}
}
}
private var metricsGrid: some View {
LazyVGrid(columns: [
GridItem(.flexible()),
GridItem(.flexible())
], spacing: 16) {
ForEach(metrics) { metric in
MetricCard(metric: metric)
}
}
}
private var balanceChart: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Balance History")
.font(.title3)
.fontWeight(.semibold)
Chart {
ForEach(balanceHistory) { history in
LineMark(
x: .value("Date", history.date),
y: .value("Balance", history.balance)
)
.foregroundStyle(Color.blue.gradient)
AreaMark(
x: .value("Date", history.date),
y: .value("Balance", history.balance)
)
.foregroundStyle(Color.blue.opacity(0.1))
}
}
.frame(height: 200)
}
.padding()
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 15))
.shadow(color: .black.opacity(0.1), radius: 5)
}
private var spendingBreakdown: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Spending Breakdown")
.font(.title3)
.fontWeight(.semibold)
Chart {
ForEach(monthlySpending, id: \.category) { item in
SectorMark(
angle: .value("Amount", item.amount),
innerRadius: .ratio(0.618),
angularInset: 1.5
)
.cornerRadius(5)
.foregroundStyle(item.category.color)
}
}
.frame(height: 200)
// Legend
VStack(spacing: 8) {
ForEach(monthlySpending, id: \.category) { item in
HStack {
Circle()
.fill(item.category.color)
.frame(width: 8, height: 8)
Text(item.category.rawValue)
.font(.caption)
Spacer()
Text("$\(item.amount, specifier: "%.2f")")
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
}
.padding()
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 15))
.shadow(color: .black.opacity(0.1), radius: 5)
}
private var recentTransactions: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Recent Transactions")
.font(.title3)
.fontWeight(.semibold)
ForEach(transactions) { transaction in
TransactionRow(transaction: transaction)
}
}
}
}
struct MetricCard: View {
let metric: FinancialMetric
var body: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
Image(systemName: metric.icon)
.foregroundStyle(metric.color)
Text(metric.title)
.foregroundStyle(.secondary)
}
.font(.subheadline)
HStack(alignment: .firstTextBaseline, spacing: 8) {
Text("$\(metric.value, specifier: "%.2f")")
.font(.title3)
.fontWeight(.bold)
if metric.trend != 0 {
HStack(spacing: 2) {
Image(systemName: metric.trend > 0 ? "arrow.up.right" : "arrow.down.right")
Text("\(abs(metric.trend), specifier: "%.1f")%")
}
.font(.caption)
.foregroundStyle(metric.trend > 0 ? .green : .red)
}
}
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 15))
.shadow(color: .black.opacity(0.1), radius: 5)
}
}
struct TransactionRow: View {
let transaction: Transaction
var body: some View {
HStack(spacing: 16) {
Image(systemName: transaction.category.icon)
.font(.title2)
.foregroundStyle(transaction.category.color)
.frame(width: 44, height: 44)
.background(transaction.category.color.opacity(0.1))
.clipShape(Circle())
VStack(alignment: .leading, spacing: 4) {
Text(transaction.title)
.fontWeight(.medium)
Text(transaction.date, style: .date)
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer()
Text(transaction.isIncome ? "+$\(transaction.amount, specifier: "%.2f")" : "-$\(transaction.amount, specifier: "%.2f")")
.fontWeight(.medium)
.foregroundStyle(transaction.isIncome ? .green : .primary)
}
.padding()
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 15))
.shadow(color: .black.opacity(0.1), radius: 5)
}
}
More Templates
View All TemplatesSimilar Blogs
View All Articles
How to Translate Xcode String Catalogs with AI
Learn how to efficiently translate Xcode string catalogs using AI fast, streamlining localization for your iOS and SwiftUI applications.

How to optimize your SwiftUI app in 2026
Discover top strategies to optimize your SwiftUI app in 2026, enhancing performance, responsiveness, and maintainability with modern concurrency.

SwiftUI: iOS Confirmation Alert (Confirm + Cancel)
SwiftUI iOS confirmation alert with Confirm and Cancel buttons. Beginners guide to building safe actions, destructive deletes, and commit dialogs.

SwiftUI: IOS Haptic Feedback Guide 2026
Add click to vibrate haptic feedback in SwiftUI. Full guide to UIImpactFeedbackgenerator, success, error, selection, and tap vibration patterns with code.
Code copied to clipboard!