19.4 C
London
Saturday, May 18, 2024

ios – Is it attainable so as to add a customized transition to TabView kids when web page modifications?


If you need to have the ability to specify a Transition for every of the tabs utilizing a view modifier, such as you did within the instance code, it’s best to write down your personal TabView.

Right here is an tailored model of the customized “tab view” I wrote right here, that makes the tabs look extra like tabs. I’ve additionally added a tabTransition modifier to let you select a Transition.

struct CustomTabView<Content material: View, Choice: Hashable>: View {
    
    @Binding var selectedTab: Choice
    
    @ViewBuilder let content material: () -> Content material
    
    var physique: some View {
        Extract(content material) { views in
            ForEach(views) { view in
                if view.id(as: Choice.self) == selectedTab {
                    view
                        .body(maxWidth: .infinity, maxHeight: .infinity)
                        .transition(view[TabTransitionTrait.self])
                }
            }
        }
        .safeAreaInset(edge: .backside) {
            HStack {
                Spacer()
                ExtractMulti(content material) { views in
                    ForEach(views) { view in
                        Group {
                            if let label = view[CustomTabItemTrait.self] {
                                label
                            } else {
                                Textual content("Unnamed")
                            }
                        }
                        .onTapGesture {
                            if let choice = view.id(as: Choice.self) {
                                selectedTab = choice
                            }
                        }
                        .foregroundStyle(
                            view.id(as: Choice.self) == selectedTab ?
                                AnyShapeStyle(Coloration.accentColor) : AnyShapeStyle(.opacity(1))
                        )
                        Spacer()
                    }
                }
            }
        }
    }
}

extension View {
    func customTabItem<Content material: View>(@ViewBuilder content material: () -> Content material) -> some View {
        _trait(CustomTabItemTrait.self, AnyView(content material()))
    }
}

struct CustomTabItemTrait: _ViewTraitKey {
    static let defaultValue: AnyView? = nil
}

extension View {
    func tabTransition<T: Transition>(_ transition: T) -> some View {
        _trait(TabTransitionTrait.self, AnyTransition(transition))
    }
}

struct TabTransitionTrait: _ViewTraitKey {
    static let defaultValue: AnyTransition = .identification
}

// MARK: View Extractor - https://github.com/GeorgeElsham/ViewExtractor

public struct Extract<Content material: View, ViewsContent: View>: View {
    let content material: () -> Content material
    let views: (Views) -> ViewsContent

    public init(_ content material: Content material, @ViewBuilder views: @escaping (Views) -> ViewsContent) {
        self.content material = { content material }
        self.views = views
    }

    public init(@ViewBuilder _ content material: @escaping () -> Content material, @ViewBuilder views: @escaping (Views) -> ViewsContent) {
        self.content material = content material
        self.views = views
    }

    public var physique: some View {
        _VariadicView.Tree(
            UnaryViewRoot(views: views),
            content material: content material
        )
    }
}

fileprivate struct UnaryViewRoot<Content material: View>: _VariadicView_UnaryViewRoot {
    let views: (Views) -> Content material

    func physique(kids: Views) -> some View {
        views(kids)
    }
}

public struct ExtractMulti<Content material: View, ViewsContent: View>: View {
    let content material: () -> Content material
    let views: (Views) -> ViewsContent

    public init(_ content material: Content material, @ViewBuilder views: @escaping (Views) -> ViewsContent) {
        self.content material = { content material }
        self.views = views
    }

    public init(@ViewBuilder _ content material: @escaping () -> Content material, @ViewBuilder views: @escaping (Views) -> ViewsContent) {
        self.content material = content material
        self.views = views
    }

    public var physique: some View {
        _VariadicView.Tree(
            MultiViewRoot(views: views),
            content material: content material
        )
    }
}

fileprivate struct MultiViewRoot<Content material: View>: _VariadicView_MultiViewRoot {
    let views: (Views) -> Content material

    func physique(kids: Views) -> some View {
        views(kids)
    }
}

public typealias Views = _VariadicView.Kids

Instance utilization:

struct ContentView: View {
    @State var selectedTab = 0
    var physique: some View {
        CustomTabView(selectedTab: $selectedTab.animation()) {
            Coloration.blue
                .id(0) // you could use .id as a substitute of .tag to specify the choice worth
                .customTabItem {
                    Label("Baz", systemImage: "circle")
                }
                .tabTransition(.push(from: .main))
            
            Coloration.yellow
                .id(1)
                .customTabItem {
                    Label("Foo", systemImage: "globe")
                }
                .tabTransition(.push(from: .backside))
            
            Coloration.inexperienced
                .id(2)
                .customTabItem {
                    Label("Bar", systemImage: "rectangle")
                }
                .tabTransition(.opacity)
        }
    }
}

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here