在 SwiftUI 中使用分段式选择器在两个页面之间滑动
Posted
技术标签:
【中文标题】在 SwiftUI 中使用分段式选择器在两个页面之间滑动【英文标题】:Swipe between two pages with Segmented-style Picker in SwiftUI 【发布时间】:2020-01-10 21:37:14 【问题描述】:我有一个 Picker
和 .pickerStyle(SegmentedPickerStyle())
来使其成为分段控件。我想让页面在它们之间平滑滑动,而不是使用条件语句替换视图。
这是我到目前为止所做的 GIF:
这是目前为止的代码(由if
控制,而不是在不同页面之间切换):
struct AuthView: View
@State private var authPath = 0
/* ... */
var body: some View
VStack
Picker(selection: $authPath, label: Text("Authentication Path"))
Text("Log In").tag(0)
Text("Sign Up").tag(1)
.pickerStyle(SegmentedPickerStyle())
Spacer()
if authPath == 0
LogInView(/* ... */)
else
SignUpView(/* ... */)
Spacer()
.padding()
.background(Color("Color.Background").edgesIgnoringSafeArea(.all))
我想要类似于UIPageViewController
的东西。如果有 SwiftUI 版本或好的替代方案,那真的很有帮助。
但是,如果我确实需要使用 UIViewRepresentable
来使用 UIKit,我不知道如何使用 SwiftUI 来实现它。
【问题讨论】:
【参考方案1】:这是可能的方法(请注意,为了测试它需要使用模拟器,因为预览不能正确处理 .move
转换)
Demo(只是使用了stub view,动画和transition的参数可以配置,但思路不变)。
注意:过渡视图的背景应该是不透明的(这里使用Color.white
),否则过渡看起来……不好。
struct TestTwoViewMoveIn: View
@State private var authPath: Int? = nil
/* ... */
var body: some View
VStack
Picker(selection: Binding<Int>(
get: self.authPath ?? 0 ,
set: tag in
withAnimation // needed explicit for transitions
self.authPath = tag
),
label: Text("Authentication Path"))
Text("Log In").tag(0)
Text("Sign Up").tag(1)
.pickerStyle(SegmentedPickerStyle())
Spacer()
ZStack
Rectangle().fill(Color.clear)
if nil == authPath
LogInView(/* ... */)
.background(Color.white) // << set your background
if authPath == 0
LogInView(/* ... */)
.background(Color.white) // << set your background
.transition(.move(edge: .leading))
if authPath == 1
SignUpView(/* ... */)
.background(Color.white) // << set your background
.transition(.move(edge: .trailing))
Spacer()
.padding()
.background(Color("Color.Background").edgesIgnoringSafeArea(.all))
【讨论】:
【参考方案2】:您可以将LoginView
和SignupView
包装在某个容器中以使其具有动画效果。
var body: some View
VStack
Picker(selection: $authPath, label: Text("Authentication Path"))
// withAnimation(Animation.easeInOut.speed(0.5))
Text("Log In").tag(0)
Text("Sign Up").tag(1)
//
.pickerStyle(SegmentedPickerStyle())
Spacer()
if authPath == 0
NavigationView
Text("1")
.animation(.default).transition(.move(edge: .leading))
//(/* ... */)
else
NavigationView
Text("2")
.animation(.default).transition(.move(edge: .leading))
//(/* ... */)
Spacer()
.padding()
.background(Color("Color.Background").edgesIgnoringSafeArea(.all))
【讨论】:
【参考方案3】:这些其他答案为我指明了正确的方向,但代码似乎有点冗长或没有按预期运行。
以下是让我的工作发生的变化:
已将填充添加到Picker
。
删除了 VStack
末尾的填充。
if-else
已更改为 2 个if
s。
为每个LogInView
和SignInView
添加了animation
、transition
和padding
修饰符。
原文:
struct AuthView: View
@State private var authPath = 0
/* ... */
var body: some View
VStack
Picker(selection: $authPath, label: Text("Authentication Path"))
Text("Log In").tag(0)
Text("Sign Up").tag(1)
.pickerStyle(SegmentedPickerStyle())
Spacer()
if authPath == 0
LogInView(/* ... */)
else
SignUpView(/* ... */)
Spacer()
.padding()
.background(Color("Color.Background").edgesIgnoringSafeArea(.all))
新:
struct AuthView: View
@State private var authPath = 0
/* ... */
var body: some View
VStack
Picker(selection: $authPath, label: Text("Authentication Path"))
Text("Log In").tag(0)
Text("Sign Up").tag(1)
.pickerStyle(SegmentedPickerStyle())
.padding()
Spacer()
if authPath == 0
LogInView(/* ... */)
.animation(.default)
.transition(.move(edge: .leading))
.padding()
if authPath == 1
SignUpView(/* ... */)
.animation(.default)
.transition(.move(edge: .trailing))
.padding()
Spacer()
.background(Color("Color.Background").edgesIgnoringSafeArea(.all))
【讨论】:
以上是关于在 SwiftUI 中使用分段式选择器在两个页面之间滑动的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 选择器在 ObservedObject 公共变量更新期间滚动时跳转