Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 22514

Why Custom TabBar views are re-creating?

$
0
0

I have something like this:

import SwiftUIstruct ContentView: View {    @State private var showOnboarding = false    @State private var dismissOnboarding = false    @StateObject private var viewModel = ContentViewModel(storage: Storage.shared)    var body: some View {        ZStack {            Color.primary                .edgesIgnoringSafeArea(.all)            CustomTabBarContainerView(selection: $viewModel.selection) {                NavigationStack {                    HomeView()                        .navigationTitle("Home")                }                .tabBarItem(tab: .home, selection: $viewModel.selection)                NavigationStack {                    SecondView()                        .navigationTitle("Favorites")                }                .tabBarItem(tab: .voice, selection: $viewModel.selection)            }            .disabled(showOnboarding)        }        .onChange(of: showOnboarding) { isPresented in            if !isPresented {                viewModel.finishOnboarding()            }        }        .onAppear {            withAnimation {                showOnboarding = !Storage.shared.isOnboardingFinished            }        }        .onChange(of: dismissOnboarding) { newValue in            if newValue {                withAnimation {                    showOnboarding = false                }            }        }.sheet(isPresented: $showOnboarding) {            OnboardingContentView(dismiss: $dismissOnboarding)        }    }}#Preview {    ContentView()}

Then I have

 struct CustomTabBarContainerView<Content: View>: View {        // MARK: - Private Properties        private let content: Content        @State private var tabs: [TabBarItem] = []        @Binding private var selection: TabBarItem        var body: some View {            VStack(spacing: 0) {                ZStack {                    content                }                CustomTabBarView(tabs: tabs, selection: $selection)            }            .onPreferenceChange(TabBarItemPreferenceKey.self, perform: { tabs in                self.tabs = tabs            })        }        init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content) {            self._selection = selection            self.content = content()        }    }    #Preview {        CustomTabBarContainerView(selection: .constant(.home)) {            Color.gray        }    }and: struct TabBarHeightPreferenceKey: PreferenceKey {    static var defaultValue: CGFloat = 0    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {        value = max(value, nextValue())    }}struct CustomTabBarView: View {    let tabs: [TabBarItem]    @Binding var selection: TabBarItem    @State var tabBarHeight: CGFloat = 0    var body: some View {        RoundedRectangle(cornerRadius: 50)            .fill(Color.gray.opacity(0.2))            .overlay(                HStack(spacing: 0) {                    ForEach(tabs, id: \.self) { tab in                        tabView(tab: tab)                            .getDimensions { dimensions in                                tabBarHeight = dimensions.height                            }                            .onTapGesture {                                switchTo(tab: tab)                            }                    }                }            )            .frame(height: tabBarHeight)            .padding(.horizontal, 20)    }}// MARK: - Private Methodsprivate extension CustomTabBarView {    func tabView(tab: TabBarItem) -> some View {        VStack {            Image(systemName: tab.iconName)                .font(.subheadline)            Text(tab.title)                .font(.system(size: 10, weight: .semibold, design: .rounded))        }        .frame(maxWidth: .infinity)        .padding(.top, 25)        .padding(.bottom,25)        .foregroundStyle(selection == tab ? tab.color : .gray)    }    func switchTo(tab: TabBarItem) {        selection = tab    }}#Preview {    VStack {        Spacer()        CustomTabBarView(tabs: TabBarItem.allCases, selection: .constant(.home))    }}

I know this is a lot of code, but I really can't figure out which part of code is relevant here. The thing is, each time I switch the tab, I have my HomeView and SecondView re-creating (aka their inits are called each time). This seems to me like some quite of a mistake in some part of my code, cause if change my custom tab bar, to native TabBar, these views don't get initialized every time, but only once. I guess I am missing here something pretty crucial?

Also here is the extension of View that I use to get a dimensions a TabBar and update its "background":

func getDimensions(action: @escaping (_ rect: CGRect) -> Void) -> some View {        self.background(            GeometryReader { geometry in                Color.clear                    .preference(key: ViewDimensionsPreferenceKey.self, value: geometry.frame(in: .global))                    .onPreferenceChange(ViewDimensionsPreferenceKey.self) { value in                        action(value)                    }            }        )    }

Viewing all articles
Browse latest Browse all 22514

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>