类似于 Slack 的 SwiftUI 导航

标签 swift swiftui

我正在尝试制作一个类似于 Slack 应用程序的导航 UI,其中我有一个覆盖菜单导航屏幕的主屏幕。我创建了一个使主屏幕可拖动的 ViewModifier。现在我需要添加功能,以便在蓝色菜单屏幕上点击“主页”时,白色主页 View 动画回到中心。我的想法是在全局 AppState 中跟踪 NavigationState:

enum NavigationSelection {
  case menu
  case home
}

final class AppState: ObservableObject {
  let objectWillChange = PassthroughSubject<Void, Never>()
  @Published var currentNavigationSelection: NavigationSelection = .home 
}

然后当用户点击“主页”时,让它更新 AppState 的 currentNavigationSelection,并让 Draggable View 根据 currentNavigationSelection 确定其偏移量。我真的不确定这种方法,我很难在新的 SwiftUI 风格中考虑它。任何建议将不胜感激。

enter image description here

View 层次结构如下所示:

 var body: some View {
    ZStack {
        Menu()
        HomeTabView()
    }
}

并且 HomeTabView 应用了可拖动的 ViewModifier:

struct Slidable: ViewModifier {

  @EnvironmentObject var app: AppState

  @State private var viewState = SlidableViewDragState.normal.defaultPosition
  @State private var currentPosition: SlidableViewDragState = .normal {
    didSet {
        self.viewState = self.currentPosition.defaultPosition
    }
  }

  func body(content: Content) -> some View {
    return content
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight:
        .infinity, alignment: Alignment.topLeading)
        .offset(self.viewState)
        .animation(.interactiveSpring())
    .gesture(
        DragGesture()
            .onChanged({ (value) in
                self.viewState = self.currentPosition.applyXTranslation(x: value.translation.width)
            })
            .onEnded({ (value) in
                if value.translation.width < 0 && self.currentPosition == .normal {
                    return
                }
                if abs(value.translation.width) > self.currentPosition.switchThreshold {
                    self.currentPosition = self.currentPosition.oppositePosition
                    if self.currentPosition == .menuVisible {
                        self.app.currentNavigationSelection = .menu
                    }
                } else {
                    self.viewState = self.currentPosition.defaultPosition
                }
            })
    )
  }
}

最佳答案

移动两个 View

您目前如何定义两者的位置?以我有限的经验,我会使用 ZStack 嵌入 HomeViewMenuView。这样您就可以独立移动 View 。

然后您使用一个point 变量作为状态,并使DragGesture 设置point。然后在拖动结束时确定 point 设置的结束位置。

point 是偏移计算的一部分。您可以使用 .offset(x: point.x) 计算菜单偏移,使用 .offset(x: -Self.maxOffset - Self.minusHomeWidth/2 + point .x).

minusHomeWidth 是您在主屏幕上时菜单仍然显示的宽度。

定义的最小值和最大值的变量:

static let minOffset: CGFloat = 0
static let maxOffset: CGFloat = UIScreen.main.bounds.width - Self.minusHomeWidth
static let minusHomeWidth: CGFloat = UIScreen.main.bounds.width / 10

然后你可以让它移动到主视图宽度

Button(action: {
    self.point = CGPoint(x: Self.maxOffset, y: 0)
}) { Text("Go to Home") }

关于类似于 Slack 的 SwiftUI 导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57538560/

相关文章:

swift - 如何添加 onCommit、isEditing 以及自定义绑定(bind)到自定义 TextView 的能力?

ios - 使用 iOS MobileSDK 同步执行 SalesForce SOQL 查询

ios - MessageKit 不显示消息输入栏 Swift 5

ios - 如何使 Swift 中的所有屏幕保持一致?

ios - 归档时 Swift 嵌入式框架构建失败

ios - 如何更改搜索栏中的边框和图标(Swift)

ios - 类型 'any View' 不能符合泛型协议(protocol)上的 'View'

ios - SwiftUI View 修改器 : How to create view modifier functions without using View extensions?

swift - Xcode swift ui 错误 'KeyPathComparator' 仅适用于 macOS 12.0 或更新版本

ios - 我们可以在 SwiftUI 中禁用 Textfield 的复制/粘贴选项吗?