【问题标题】:SwiftUI View Transition matching to an Segmented PickerSwiftUI 视图转换匹配分段选择器
【发布时间】:2021-02-18 17:52:32
【问题描述】:

是否可以根据 PickerSegmentedPickerStyle() 样式从侧面动画进出的三个(超过 2 个!)视图?

选择器中只有 2 个项目会使作业静态化,因此第一个视图上的 .transition(.move(edge: .leading)) 和最后一个视图上的 .transition(.move(edge: .trailing)) 就足够了。但是超过 2 个呢?

也许有一种方法可以使转换的edge: ... 参数动态设置为.leading.trailing,具体取决于绑定的新值是大于还是小于当前值。

我创建了以下草图来演示具有不同转换的相同视图(视图 2)的问题,具体取决于选择了右侧还是左侧的视图。请看这只是一个例子,问题不仅限于三个片段,也不仅仅是中间视图,也不仅仅是消失的过渡等。

【问题讨论】:

  • 你能分享一张所需结果的图片吗?
  • 我确信这是可能的。请提供一些代码。
  • 我在开始编码之前就在考虑这个问题,所以不幸的是我没有,图片也可能无法很好地描述所需的动画,想象一下分段控件选择器,每个分段负责显示它下面的专用视图。视图动画(从左/右滑入/滑出)应该与 Picker(标准的分段控件选择器,我们都知道来自苹果)中的白色背景栏的移动相匹配,这表明当前的选择。
  • 我添加了一个草图,描述了一个特定示例案例所需的行为,该案例应该很好地解释了所需的结果和整体问题。

标签: swift swiftui swiftui-animation


【解决方案1】:

更新秘诀是确保过渡以动画触发,并在这样做之前告诉它前进的方向。试试这个:

class TabControllerContext : ObservableObject {
    @Published var selected = panels.one { didSet {
        if previous != selected {
            insertion = selected.makeMove(previous)
            removal = previous.makeMove(selected)

            withAnimation {
                trigger = selected
                previous = selected
            }
        }
    }}
    
    @Published var trigger = panels.one
    @Published var previous = panels.one
    var insertion : AnyTransition = .move(edge: .leading)
    var removal : AnyTransition = .move(edge: .trailing)
}

struct TabsWithTransitionsView: View {
    @EnvironmentObject var context : TabControllerContext
    
    var body: some View {
        VStack {
            Picker("Select Panel", selection: $context.selected) {
                ForEach(panels.allCases) { panel in
                    panel.label.tag(panel)
                }
            }.pickerStyle(SegmentedPickerStyle())
            
            ForEach(panels.allCases) { panel in
                if context.trigger == panel {
                    panel.label
                        .background(panel.color)
                        .transition(.asymmetric(insertion: context.insertion, removal: context.removal))
                }
            }
        }
    }
}

enum panels : Int, CaseIterable, Identifiable {
    case one = 1
    case two = 2
    case three = 3
    
    var label : some View {
        switch self {
        case .one:
            return Label("Tab One", systemImage: "1.circle")
        case .two:
            return Label("Tab Two", systemImage: "2.square")
        case .three:
            return Label("Tab Three", systemImage: "asterisk.circle")
        }
    }
    
    var color : Color {
        switch self {
        case .one: return Color.red.opacity(0.5)
        case .two: return Color.green.opacity(0.5)
        case .three: return Color.blue.opacity(0.5)
        }
    }
    
    func makeMove(_ otherPanel: panels) -> AnyTransition {
        return otherPanel.rawValue < self.rawValue ? .move(edge: .trailing) : .move(edge: .leading)
    }
    
    // so the enum can be indentified when enumerated
    var id : Int { self.rawValue }
}

struct TabsWithTransitionsView_Previews: PreviewProvider {
    static var previews: some View {
        TabsWithTransitionsView().environmentObject(TabControllerContext())
    }
}

【讨论】:

  • 我不明白这应该如何工作,因为除了最右边或最左边之外的每个视图都必须从左右滑入,具体取决于新选择是在其右侧还是左侧.
  • @lenny 添加了逻辑以使这些过渡动态化。请尝试更新后的代码。
  • 这完全成功了!谢谢你的详细示例,我实际上能够将其分解为一个自定义绑定和两个用于输入/输出转换的状态变量。
  • 不客气!这张照片很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多