10.2 C
New York
Friday, March 21, 2025

ios – Swiping screens inside a TabView with a GeometryReader would not apply the slide animation


I am a newbie to SwiftUI and I am experimenting with animations. The animation styling for my backside tabs work as anticipated once I press on every icon in addition to if I swipe on the display screen to change between the tabs. However once I attempt one thing comparable for my prime tabs, the slide animation for transitioning the chosen background coloration would not work once I swipe between the nested screens, it solely works once I press on the tab identify (button).

I’ve discovered a publish that is additionally having animation points utilizing GeometryReader nevertheless it would not appear to match my use case.

The one distinction between my prime and backside tabs is that the highest tabs use a GeometryReader, is that this a typical points? Are there any workarounds for this drawback? Any steering on the best way to clear up that is enormously appreciated.

demo

BottomTabs.swift

import SwiftUI;

struct BottomTabs: View {
    
    @Binding var tab: Int;
    
    var physique: some View {
        
        HStack {
            
                
            Button(motion: {

                withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {

                    tab = 0;

                }

            }) {
                
                VStack {
                    
                    Picture(systemName: "baseball.fill").resizable()
                        .scaledToFit()
                        .body(width: 16, peak: 16)
                        .foregroundStyle(

                            LinearGradient(colours: [(tab == 0) ? .green : .white, (tab == 0) ? .purple : .white],
                                           startPoint: .prime, endPoint: .backside)
                            
                        ).scaleEffect((tab == 0) ? 1.2 : 1)
                         .animation(.easeInOut(length: 0.3), worth: tab);
                    
                    Circle()
                        .fill(.yellow)
                        .body(width: (tab == 0) ? 5 : 0, peak: (tab == 0) ? 5 : 0)
                        .padding(.prime, (tab == 0) ? 2 : 0)
                        .opacity((tab == 0) ? 1 : 0)
                        .animation(.easeInOut(length: 0.3), worth: tab);
                    
                }

            }.padding(.horizontal, 10)
                            
            Button(motion: {
                
                withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {
                    
                    tab = 1;
                    
                }
                
            }) {
                
                VStack {
                    
                    Picture(systemName: "coronary heart.fill").resizable()
                        .scaledToFit()
                        .body(width: 16, peak: 16)
                        .foregroundStyle(
                            
                            LinearGradient(colours: [(tab == 1) ? .green : .white, (tab == 1) ? .purple : .white],
                                           startPoint: .prime, endPoint: .backside)
                            
                        )
                        .scaleEffect((tab == 1) ? 1.2 : 1)
                        .animation(.easeInOut(length: 0.3), worth: tab);
                    
                    Circle().fill(.yellow)
                        .body(width: (tab == 1) ? 5 : 0, peak: (tab == 1) ? 5 : 0)
                        .opacity((tab == 1) ? 1 : 0)
                        .padding(.prime, (tab == 1) ? 2 : 0)
                        .animation(.easeInOut(length: 0.3), worth: tab);
                    
                }
                
            }.padding(.horizontal, 10)
                            
            Button(motion: {
                
                withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {
                    
                    tab = 2;
                    
                }
                
            }) {
                
                VStack {
                    
                    Picture(systemName: "basketball.fill").resizable()
                        .scaledToFit()
                        .body(width: 16, peak: 16)
                        .foregroundStyle(
                            
                            LinearGradient(colours: [(tab == 2) ? .green : .white, (tab == 2) ? .purple : .white],
                                           startPoint: .prime, endPoint: .backside)
                            
                        )
                        .scaleEffect((tab == 2) ? 1.2 : 1)
                        .animation(.easeInOut(length: 0.3), worth: tab);
                    
                    Circle().fill(.yellow)
                        .body(width: (tab == 2) ? 5 : 0, peak: (tab == 2) ? 5 : 0)
                        .opacity((tab == 2) ? 1 : 0)
                        .padding(.prime, (tab == 2) ? 2 : 0)
                        .animation(.easeInOut(length: 0.3), worth: tab);
                    
                }
                    
            }.padding(.horizontal, 10)

        }.body(peak: 30)
            .padding(.vertical, 20)
            .padding(.horizontal, 30)
         .background(
            
            RoundedRectangle(cornerRadius: 20).fill(.black)
            
         ).padding(.backside, 10);
        
    }
    
}

ContentView.swift

import SwiftUI;

struct ContentView: View {

    @State personal var tab: Int = 0;
    @State personal var tag: Int = 0;

    var physique: some View {

        ZStack(alignment: .backside) {

            TabView(choice: $tab) {

                NavigationStack {
                    
                    ZStack(alignment: .prime) {

                        TabView(choice: $tag) {

                            ScrollView(showsIndicators: false) {
                                
                                LazyVStack {
                                    
                                    ForEach(0..<500, id: .self) { i in
                                        
                                        Textual content("(i + 1). TRENDING HOME SCREEN");
                                        
                                    }
                                    
                                }
                                
                            }.tag(0)
                                
                            ScrollView(showsIndicators: false) {
                                
                                LazyVStack {
                                    
                                    ForEach(0..<500, id: .self) { i in
                                        
                                        Textual content("(i + 1). FOLLOWING HOME SCREEN");
                                        
                                    }
                                    
                                }
                                
                            }.tag(1)
                                
                                
                            ScrollView(showsIndicators: false) {
                                
                                LazyVStack {
                                    
                                    ForEach(0..<500, id: .self) { i in
                                        
                                        Textual content("(i + 1). EVENTS HOME SCREEN");
                                        
                                    }
                                    
                                }
                                
                            }.tag(2)
                                                            
                    }.tabViewStyle(PageTabViewStyle(indexDisplayMode: .by no means))

                        .toolbar {
                            
                            ToolbarItemGroup(placement: .navigationBarLeading) {
                                
                                Button(motion: {
                                    
                                    
                                    
                                }) {
                                    
                                    Picture(systemName: "basketball.fill")
                                        .resizable()
                                        .scaledToFit()
                                        .body(width: 50, peak: 50)
                                        .foregroundColor(.black);
                                    
                                }
                                .padding(.prime, 50)
                                .padding(.main, 20);
                                
                            }
                            
                            ToolbarItemGroup(placement: .navigationBarTrailing) {
                                
                                Button(motion: {
                                    
                                    
                                }) {
                                    
                                    Picture(systemName: "baseball.fill")
                                        .resizable()
                                        .scaledToFit()
                                        .body(width: 50, peak: 50)
                                        .foregroundColor(.black);
                                    
                                }.padding(.prime, 50)
                                    .padding(.trailing, 20);
                                
                            }
                            
                        }
                        .toolbarBackground(.hidden, for: .navigationBar)
                        
                        TopTabs(tab: $tag).padding(.prime, 60)
                        
                    }
                    .ignoresSafeArea()

                }
                .tag(0)

                ScrollView(showsIndicators: false) {
                    
                    LazyVStack {
                        
                        ForEach(0..<1000, id: .self) { i in
                            
                            Textual content("(i + 1). LIKES SCREEN");
                            
                        }
                        
                    }
                    
                }.tag(1)
                
                ScrollView(showsIndicators: false) {
                    
                    LazyVStack {
                        
                        ForEach(0..<2000, id: .self) { i in
                            
                            Textual content("(i + 1). SPORTS SCREEN");
                            
                        }
                        
                    }
                    
                }.tag(2)
                
            }.tabViewStyle(PageTabViewStyle(indexDisplayMode: .by no means));
            
            BottomTabs(tab: $tab);
            
        }
        .ignoresSafeArea()
        
    }
    
}

#Preview {
    
    ContentView();
    
}

TopTabs.swift

import SwiftUI

struct TopTabs: View {
    
    @Binding var tab: Int
    @Namespace personal var animation
    
    var physique: some View {
        GeometryReader { geometry in
            
            let containerWidth = geometry.dimension.width * 0.9
            let tabWidth = containerWidth / 3
            
            ZStack(alignment: .main) {
                
                RoundedRectangle(cornerRadius: 50)
                    .fill(Shade.yellow)
                    .body(width: tabWidth, peak: 40)
                    .matchedGeometryEffect(id: "tabBackground", in: animation)
                    .offset(x: CGFloat(tab) * tabWidth)
                
                HStack(spacing: 0) {
                    
                    Button(motion: {
                        
                        withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {
                            
                            tab = 0
                            
                        }
                        
                    }) {
                        
                        Textual content("Trending")
                            .font(Font.customized("Gilroy-Medium", dimension: 14))
                            .foregroundColor(tab == 0 ? .black : .white)
                        
                    }
                    .body(width: tabWidth, peak: 40)
                    
                    Button(motion: {
                        
                        withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {
                            
                            tab = 1
                            
                        }
                        
                    }) {
                        
                        Textual content("Following")
                            .font(Font.customized("Gilroy-Medium", dimension: 14))
                            .foregroundColor(tab == 1 ? .black : .white)
                        
                    }
                    .body(width: tabWidth, peak: 40)
                    
                    Button(motion: {
                        
                        withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) {
                            
                            tab = 2
                            
                        }
                        
                    }) {
                        
                        Textual content("Occasions")
                            .font(Font.customized("Gilroy-Medium", dimension: 14))
                            .foregroundColor(tab == 2 ? .black : .white)
                        
                    }
                    .body(width: tabWidth, peak: 40)
                    
                }
            }
            .body(width: containerWidth, peak: 40)
            .background(
                
                RoundedRectangle(cornerRadius: 50)
                    .fill(Shade.grey)
                
            )
            .masks(RoundedRectangle(cornerRadius: 50))
            .padding(.prime, 20)
            .body(maxWidth: .infinity)
            
        }
        .transition(AnyTransition.opacity.animation(.easeInOut(length: 0.2)))
        
    }
    
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles