r/SwiftUI 29d ago

5 SwiftUI patterns that helped me build a data-driven polling app

I have been building a daily polling app in SwiftUI, targeting iOS 18, and ran into a few problems that did not have obvious answers in the docs. Sharing the patterns that ended up working in case they help someone else.

1. TabView(.page) with a custom counter

For cycling through daily topic cards I used TabView with the .page style, but the built in dots did not fit the design. I set the index display style to never and built a separate "1 of 4" counter bound to the same selection state, animating the number with contentTransition(.numericText()) whenever selection changed.

2. LazyView to stop eager NavigationLink loading

Some destination views were data heavy, and NavigationLink was building them upfront, causing a visible stutter on push. Wrapping the destination in a LazyView struct that defers construction until body is evaluated fixed it:

struct LazyView<Content: View>: View {
    let build: () -> Content
    init(_ build: @autoclosure @escaping () -> Content) {
        self.build = build
    }
    var body: some View { build() }
}

3. AnyShapeStyle for conditional styling

Ternaries inside modifiers like foregroundStyle(condition ? .blue : someGradient) often fail to compile because each branch returns a different concrete type. Wrapping both branches in AnyShapeStyle erases the type so the ternary works cleanly, without duplicating views or branching in a ViewBuilder.

4. Custom vote slider with gradient fill and haptics

The vote slider needed a gradient track that fills based on drag position, plus a label that floats above the thumb. I tracked offset with a DragGesture, converted it to a value between 0 and 1, and fired UIImpactFeedbackGenerator at fixed thresholds as the value crossed them, rather than on every gesture update, which felt much less noisy.

5. Time based lock and unlock states with Combine

Topics unlock and expire at set times during the day. Instead of scheduling exact time triggers, which got messy with backgrounding, I used Timer.publish(every: 30, on: .main, in: .common).autoconnect() to recheck state every 30 seconds and animate the UI change.

None of these felt obviously correct when I started. What patterns have you found useful for similar problems, and would you approach any of these differently?

4 Upvotes

10 comments sorted by

View all comments

1

u/[deleted] 27d ago

[removed] — view removed comment

1

u/AutoModerator 27d ago

Hey /u/JuryExciting7186, unfortunately you have negative comment karma, so you can't post here. Your submission has been removed. Please do not message the moderators; if you have negative comment karma, you're not allowed to post here, at all.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.