SwiftUI中的选项卡栏中间按钮实用程序函数

y1aodyip  于 2023-05-16  发布在  Swift
关注(0)|答案(4)|浏览(147)

我试图重现一个像tabBar这样的“Instagram”,它在中间有一个“实用程序”按钮,不一定属于tabBar生态系统。
我附上了这个GIF来显示我追求的行为。描述问题。中间的选项卡栏(黑色加号)是单击ActionSheet,而不是切换视图。

我在UIKit中如何做到这一点是简单地使用

override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
    print("Selected item")
}

UITabBarDelegate的函数。但显然我们不能在SwiftUI中做到这一点,所以我们想看看人们是否尝试过任何想法。我最后的想法是简单地将其 Package 在UIView中并与SwiftUI一起使用,但希望避免这种情况并保持其原生。
我已经看到一个写在一个自定义标签栏,但想使用苹果提供的标签栏,以避免任何未来的差异。
谢谢!
编辑:让问题更清晰。

twh00eeo

twh00eeo1#

感谢Aleskey提供的精彩答案(标记为正确)。除了一篇围绕Modal编写的medium文章之外,我还对它进行了一些改进。我发现有点不一样
这是笑话。
MainTabBarData是一个可观察对象

final class MainTabBarData: ObservableObject {

    /// This is the index of the item that fires a custom action
    let customActiontemindex: Int

    let objectWillChange = PassthroughSubject<MainTabBarData, Never>()

    var previousItem: Int

    var itemSelected: Int {
        didSet {
            if itemSelected == customActiontemindex {
                previousItem = oldValue
                itemSelected = oldValue
                isCustomItemSelected = true
            }
            objectWillChange.send(self)
        }
    }

    func reset() {
        itemSelected = previousItem
        objectWillChange.send(self)
    }

    /// This is true when the user has selected the Item with the custom action
    var isCustomItemSelected: Bool = false

    init(initialIndex: Int = 1, customItemIndex: Int) {
        self.customActiontemindex = customItemIndex
        self.itemSelected = initialIndex
        self.previousItem = initialIndex
    }
}

这是TabbedView

struct TabbedView: View {

    @ObservedObject private var tabData = MainTabBarData(initialIndex: 1, customItemIndex: 2)

    var body: some View {

        TabView(selection: $tabData.itemSelected) {
            Text("First Screen")
                .tabItem {
                    VStack {
                        Image(systemName: "globe")
                            .font(.system(size: 22))
                        Text("Profile")
                    }

                }.tag(1)

            Text("Second Screen")
                .tabItem {
                    VStack {
                        Image(systemName: "plus.circle")
                            .font(.system(size: 22))
                        Text("Profile")
                    }
            }.tag(2)

            Text("Third Screen")
                .tabItem {
                    VStack {
                        Image(systemName: "number")
                            .font(.system(size: 22))
                        Text("Profile")
                    }
            }.tag(3)

        }.actionSheet(isPresented: $tabData.isCustomItemSelected) {
            ActionSheet(title: Text("SwiftUI ActionSheet"), message: Text("Action Sheet Example"),
                        buttons: [
                            .default(Text("Option 1"), action: option1),
                            .default(Text("Option 2"), action: option2),
                            .cancel(cancel)
                        ]
            )
        }


    }

    func option1() {
        tabData.reset()
        // ...
    }

    func option2() {
        tabData.reset()
        // ...
    }

    func cancel() {
        tabData.reset()
    }
}

struct TabbedView_Previews: PreviewProvider {
    static var previews: some View {
        TabbedView()
    }
}

类似的概念,只是使用了SwiftUI和合并的功能。

0s7z1bwu

0s7z1bwu2#

您可以引入新的@State属性来存储当前选项卡的旧标签。然后对除中间选项卡以外的每个选项卡.onAppear { self.oldSelectedItem = self.selectedItem }执行下一个方法。中间的选项卡将负责显示操作表,其方法如下所示:

.onAppear { 
self.shouldShowActionSheet.toggle() 
self.selectedItem = self.oldSelectedItem
}

工作示例:

import SwiftUI

struct ContentView: View {
    @State private var selectedItem = 1
    @State private var shouldShowActionSheet = false
    @State private var oldSelectedItem = 1

    var body: some View {
        TabView (selection: $selectedItem) {
            Text("Home")
                .tabItem { Image(systemName: "house") }
                .tag(1)
                .onAppear { self.oldSelectedItem = self.selectedItem }
            Text("Search")
                .tabItem { Image(systemName: "magnifyingglass") }
                .tag(2)
                .onAppear { self.oldSelectedItem = self.selectedItem }
            Text("Add")
                .tabItem { Image(systemName: "plus.circle") }
                .tag(3)
                .onAppear {
                    self.shouldShowActionSheet.toggle()
                    self.selectedItem = self.oldSelectedItem
                }
            Text("Heart")
                .tabItem { Image(systemName: "heart") }
                .tag(4)
                .onAppear { self.oldSelectedItem = self.selectedItem }
            Text("Profile")
                .tabItem { Image(systemName: "person.crop.circle") }
                .tag(5)
                .onAppear { self.oldSelectedItem = self.selectedItem }
        }
        .actionSheet(isPresented: $shouldShowActionSheet) { ActionSheet(title: Text("Title"), message: Text("Message"), buttons: [.default(Text("Option 1"), action: option1), .default(Text("Option 2"), action: option2) , .cancel()]) }
    }

    func option1() {
        // do logic 1
    }

    func option2() {
        // do logic 2
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
7d7tgy0s

7d7tgy0s3#

以前的答案没有帮助我,所以我粘贴我的完整的解决方案。

import SwiftUI
import UIKit

enum Tab {
    case map
    case recorded
}

@main
struct MyApp: App {

    @State private var selectedTab: Tab = .map
    @Environment(\.scenePhase) private var phase
    var body: some Scene {
        WindowGroup {
            VStack {
                switch selectedTab {
                case .map:
                    NavigationView {
                        FirstView()
                    }
                case .recorded:
                    NavigationView {
                        SecondView()
                    }
                }
                CustomTabView(selectedTab: $selectedTab)
                    .frame(height: 50)
            }
        }
    }
}

struct FirstView: View {
    var body: some View {
        Color(.systemGray6)
            .ignoresSafeArea()
            .navigationTitle("First view")
    }
}

struct SecondView: View {
    var body: some View {
        Color(.systemGray6)
            .ignoresSafeArea()
            .navigationTitle("second view")
    }
}

struct CustomTabView: View {
    @Binding var selectedTab: Tab
    var body: some View {
        HStack {
            Spacer()
            Button {
                selectedTab = .map
            } label: {
                VStack {
                    Image(systemName: "map")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 25, height: 25)
                    Text("Map")
                        .font(.caption2)
                }
                .foregroundColor(selectedTab == .map ? .blue : .primary)
            }
            .frame(width: 60, height: 50)
            Spacer()
            Button {
                
            } label: {
                ZStack {
                    Circle()
                        .foregroundColor(.secondary)
                        .frame(width: 80, height: 80)
                        .shadow(radius: 2)
                    Image(systemName: "plus.circle.fill")
                        .resizable()
                        .foregroundColor(.primary)
                        .frame(width: 72, height: 72)
                }
                .offset(y: -2)
            }
            Spacer()
            
            Button {
                selectedTab = .recorded
            } label: {
                VStack {
                    Image(systemName: "chart.bar")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 25, height: 25)
                    Text("Recorded")
                        .font(.caption2)
                }
                .foregroundColor(selectedTab == .recorded ? .blue : .primary)
            }
            .frame(width: 60, height: 50)
            Spacer()
        }
    }
}
omhiaaxx

omhiaaxx4#

只要用Button或任何你想要的视图做一个ZStack...确保按钮大于中间的空tabItem

struct MainTabView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            TabView {
                ContentView()
                    .tabItem {
                        Label("Tab 1", systemImage: "list.dash")
                    }

                ContentView()
                    .tabItem {
                        Label("Tab 2", systemImage: "list.dash")
                    }
                
                Spacer()
                    .tabItem {
                        EmptyView()
                    }
                
                ContentView()
                    .tabItem {
                        Label("Tab 3", systemImage: "square.and.pencil")
                    }
                
                ContentView()
                    .tabItem {
                        Label("Tab 4", systemImage: "square.and.pencil")
                    }
                
            }
            Button {
                
            } label: {
                Image(systemName: "plus")
                    .tint(Color.white)
            }
            .frame(width: 50, height: 50)
            .background(Color.green)
            .clipShape(Circle())
            
        }
    }
}

相关问题