SwiftUI Navigation 类似于 Slack

Posted

技术标签:

【中文标题】SwiftUI Navigation 类似于 Slack【英文标题】:SwiftUI Navigation similar to Slack 【发布时间】:2019-08-17 17:38:36 【问题描述】:

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

enum NavigationSelection 
  case menu
  case home


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

然后当用户点击“Home”时,让它更新 AppState 的 currentNavigationSelection,并让 Draggable 视图根据 currentNavigationSelection 确定它的偏移量。我真的不确定这种方法,而且我很难在新的 SwiftUI 样式中考虑它。任何建议将不胜感激。

视图层次结构如下所示:

 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
                
            )
    )
  

【问题讨论】:

我了解有趣的技术挑战! :) 对我来说也很有趣!但总的来说,不是所有的用户体验专家都建议不要使用汉堡包解决方案吗? 【参考方案1】:

移动两个视图

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

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

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

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

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

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") 

【讨论】:

嘿@F*** 我添加了更多代码以提供上下文。我想我明白你在说什么,我认为这将迫使我将 ViewModifier 之外的偏移计算逻辑删除到某个对象,该对象具有两个视图都受到影响的上下文,对吗? 我更新了我会怎么做的答案,我希望它更清楚一点,因为我有机会尝试它。基本上是的,必须在两者上设置偏移量,最好通过单个属性对其进行修改,因为这是最简单的。您可以将point 与在拖动结束时执行的 closure 一起传递以设置 point 应该去的位置。

以上是关于SwiftUI Navigation 类似于 Slack的主要内容,如果未能解决你的问题,请参考以下文章

React Navigation:Android 上类似于 iOS 的 Modal Stack

SwiftUI: Navigation all know

SwiftUI: Navigation all know

SwiftUI: Navigation all know

SwiftUI Navigation 多个后退按钮

SwiftUI 中的 List 是不是复用类似于 UITableView 的单元格?