A SwiftUI Todo app with dynamic lists, an About section, and external links. Designed to demonstrate modern SwiftUI patterns, including List (Swipe / Drag & Drop / Edit), Form, Inputs, sheets, navigation stacks, dynamic tabs, and custom button styles.
-
Todo List
- Dynamic list of tasks using
@StateObjectandBinding. - Supports deleting (swipe-to-delete), reordering (drag & drop), and editing tasks using
TextField.
- Dynamic list of tasks using
-
About Tab
- Large title navigation using
NavigationStackand.navigationBarTitleDisplayMode(.large). - Centered content with a bottom-aligned action button.
- Modern capsule-styled button with right icon.
- Large title navigation using
-
More Info Sheet
- Opens as a sheet from the About button.
- Navigation bar with inline title and top-right dismiss button.
- Dynamically loads links (LinkedIn, GitHub, Linktree) from a
@StateObjectview model. - Buttons open external URLs.
- Supports modern SwiftUI styling (bordered-prominent buttons, capsule shapes, and tint colors).
-
Dynamic TabView
- Tabs defined by an
AppTabenum. - Easy to add new tabs.
- Supports icons, titles, and views dynamically.
- Tabs defined by an
-
Responsive UI Tips
-
GeometryReaderused for relative sizing. -
Spacer()used for centering content and pinning buttons. - Fixed vertical/horizontal spacing via
Spacer().frame()or VStack/HStack spacing. - SF Symbols or custom asset images for icons.
-
| Todo List | Edit | Detail | About | Links |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
- Binding Extensions
.onChangeand.onEmptyto react to changes in aBinding.
func onChange(_ handler: @escaping () -> Void) -> Binding<Value> {
Binding(
get: { wrappedValue },
set: {
wrappedValue = $0
handler()
}
)
}func onEmpty<Wrapped>(_ defaultValue: Wrapped) -> Binding<Wrapped> where Value == Wrapped? {
Binding<Wrapped>(
get: { wrappedValue ?? defaultValue },
set: { wrappedValue = $0 }
)
}- Dynamic Tabs with Enum
enum AppTab: Hashable, CaseIterable {
case todoList
case about
var icon: String { ... }
var title: String { ... }
@ViewBuilder var view: some View { ... }
}



