reckart.blog
Open in
urlscan Pro
45.33.0.175
Public Scan
Submitted URL: http://reckart.blog/
Effective URL: https://reckart.blog/
Submission: On December 06 via api from US — Scanned from DE
Effective URL: https://reckart.blog/
Submission: On December 06 via api from US — Scanned from DE
Form analysis
0 forms found in the DOMText Content
TYLERRECKART BlogArchiveAbout BlogArchiveAbout WRITING A TAB VIEW CONTROLLER IN SWIFT UI Posted on June 1, 2023 In my opinion, Swift UI is a fantastic jumping-off point for less experienced developers wanting to get into iOS development. It reminds me of my earliest days of programming; just turn the clock back 15 years and swap Swift with HTML. One of the great things is that a lot of the groundwork has been laid by Apple. It's relatively easy to use Swift's built-in components to put together an app that looks at home on Apple's platforms. However, Swift's built-ins aren't exactly the most flexible components when it comes to adapting for custom UIs. Writing a custom navigation controller gives you the ability to completely control the user experience as they flow through your apps. Let's see just how easy that is. So, the first thing we'll need to do is define the view hierarchy. When working with custom navigation, I have found that it is often easier and more natural to have the tab view context live above the app's main navigation state, then nesting navigation views within each of the individual tab paths. Let's define these parent-level views through an enum declaration. enum TabView { case home case search case discover case profile case settings } Then we need to consider the context of how the tab bar UI will render in relation to our views. The simplest way to do this is by using a ZStack {} wrapper to render the tab bar higher up in the application's z-axis and thus above each of our child views. The child views will need to account for the height of the wrapper, but that is a simple calculation. All we need to do to handle the view switching is utilize a simple switch statement that will render the target view based on the application's current state. struct ContentView: View { // Define the currently active view. This should default to the home screen. @State private var activeView: TabView = .home var body: some View { ZStack { switch (activeView) { case .home: Color.red case .search: Color.blue case .discover: Color.green case .profile: Color.yellow case .settings: Color.purple } // TabBar(activeView: $activeView) } } } We can then define the markup to render the view itself. For now, each tab option will be represented by an SF Symbol until the button component is defined. struct TabBar: View { @Binding var activeView: TabView var body: some View { VStack(spacing: 0) { Spacer() Rectangle() .fill(Color(.systemGray5)) .frame(height: 0.5) HStack(spacing: 0) { Image(systemName: "1.circle.fill") .frame(maxWidth: .infinity) Image(systemName: "2.circle.fill") .frame(maxWidth: .infinity) Image(systemName: "3.circle.fill") .frame(maxWidth: .infinity) Image(systemName: "4.circle.fill") .frame(maxWidth: .infinity) Image(systemName: "5.circle.fill") .frame(maxWidth: .infinity) } .padding(.top, 15) .padding(.bottom, 30) .background(Color(.systemBackground)) } .edgesIgnoringSafeArea(.bottom) } } At this stage you should have a screen that looks similar to this: The tab bar group item is similarly straightforward in its markup: struct TabBarGroupItem: View { @Binding var activeView: TabView var targetView: TabView var image: String var body: some View { Button(action: { withAnimation(.spring()) { // Update the view. self.activeView = targetView // Provide haptic feedback. UIImpactFeedbackGenerator(style: .medium).impactOccurred() } }) { VStack(spacing: 6) { Image(systemName: image) .font(.system(size: 22, weight: .medium)) .foregroundColor(activeView == targetView ? .blue : .gray) Circle() .fill(activeView == targetView ? .blue : .clear) .frame(width: 4, height: 4) } .frame(maxWidth: .infinity) } } } With that defined, the TabBar component can be updated with the view-switching markup. HStack(spacing: 0) { TabBarGroupItem(activeView: $activeView, targetView: .home, image: "house") TabBarGroupItem(activeView: $activeView, targetView: .search, image: "magnifyingglass") TabBarGroupItem(activeView: $activeView, targetView: .discover, image: "safari") TabBarGroupItem(activeView: $activeView, targetView: .profile, image: "person.crop.circle") TabBarGroupItem(activeView: $activeView, targetView: .settings, image: "gearshape") } Now there are just a few more pieces we'll need to implement. Because we're using the z-axis to render the tab bar above the application's content, a shared Screen view can be used to provide a wrapper around the content for each tab that will let you adjust behavior and placement with a few simple modifiers. As seen in the snippet below, this is where you can use Swift's built-in transition modifiers to add some flavor to the way your views switch. struct Screen<Content>: View where Content: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() .edgesIgnoringSafeArea(.top) .transition(.push(from: .leading)) } } If you're feeling ambitious, you could easily implement an intelligent "push" animation by defining the navigation scheme and using the index of the current screen with the target screen to determine which direction to animate the push from. With that, the Screen view wrapper can be integrated into our application's root view. struct ContentView: View { @State private var activeView: TabView = .home var body: some View { ZStack { switch (activeView) { case .home: Screen { Color.red } case .search: Screen { Color.blue } case .discover: Screen { Color.green } case .profile: Screen { Color.red } case .settings: Screen { Color.purple } } TabBar(activeView: $activeView) } } } That's it! You now have a tab view controller at the root of your app that you have complete control over. You can add custom animations between views, interactions on tab changes, and more. FOR THE LOVE OF THE GAME Posted on March 14, 2023 I played Magic: The Gathering for the first time in 2006 when I was eleven years old. I remember spending time at a neighbor's house over the summer and seeing that friend's older brother playing this card game that I was wholly unfamiliar with. I was instantly interested. By this time, I had spent much of my childhood playing collectible card games. First playing Pokemon as an extension of the Gameboy games that I still hold dear, then transitioned into years of playing and collecting Yu-Gi-Oh cards as I went through elementary school. It didn't take long after I discovered Magic for the game to become the primary focus for my collecting and playing. The 15-minute walk down the road to my local game shop to spend a hard-earned $3 on a booster pack of Guildpact, Planar Chaos, and Future Sight became a weekly ritual. As I went through high school and college, my interest in the game faded over time. Programming became my driving interest, and the rest, as they say, is history. Continue Reading © 2011-2024 Tyler Reckart. All Rights Reserved. Subscribe to the RSS feed or the alternate JSON feed.