修复 SwiftUI 表单中奇怪的 DatePicker 动画行为
Fix odd DatePicker animation behaviour in SwiftUI form
我在使用 SwiftUI 表单的 DatePickers 时遇到了一些奇怪的动画行为。一张图片值一千字,所以我敢肯定一个视频值一百万字:https://imgur.com/a/UHXqXOh
我试图让日期选择器在表单中展开然后折叠,就像在 Calendar.app
中创建新事件时的行为一样
我的情况是:
- 部分中的任何展开项(最后一个除外)将正常打开,但当它关闭时,展开部分会向下滑动并淡出,而不是向上滑动并淡出。
- 该部分的最后一项滑动正确,但根本没有淡出。它只是在过渡
的 start/end 处出现然后消失
仅当表单中某处存在非 DatePicker 元素(例如文本、滑块)时才会发生这些行为(不必位于该特定部分)
这是我的内容视图:
struct ContentView: View {
@State var date = Date()
@State var isDateShown = false
var body: some View {
Form {
Section(header: Text("Title")) {
DatePicker("Test", selection:$date)
DatePicker("Test", selection:$date)
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date).datePickerStyle(WheelDatePickerStyle()).labelsHidden()
}
}
Section(header: Text("hello")) {
Text("test")
}
}
}
}
很乐意提供任何其他需要的东西
够有趣了..在新的测试版中,他们显然改变了 DatePicker。
所以如果您对 iOS 14+ 没问题...
最接近的解决方案是将日期选择器移动到它自己的部分
Form {
Section(header: Text("Title")) {
DatePicker(selection:$date1, label: {Text("Test")} )
}
DatePicker("Test", selection:$date2)
Section{
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date3).datePickerStyle(WheelDatePickerStyle()).labelsHidden()
}
}
Section(header: Text("Hello")){
Text("Hello")
}
}
对于 iOS <14,有两种可能的解决方法:1) 简单的一种是完全禁用动画,2) 复杂的一种是通过注入自定义动画修改器来减少不正确的动画
均使用 Xcode 11.4 / iOS 13.4
进行了测试
1) 简单的解决方案 - 将DatePicker
包装到容器中并将动画设置为nil
VStack {
DatePicker("Test", selection:$date).id(2)
}.animation(nil)
2) 复杂的解决方案 - 使用 a) 从我的其他解决方案中查看偏好 reader and b) animate this frame explicitly using 来获取 DatePicker
更改框架。
struct TestDatePickersInForm: View {
@State var date = Date()
@State var isDateShown = false
@State private var height = CGFloat.zero
var body: some View {
Form {
Section(header: Text("Title")) {
// demo of complex solution
VStack {
DatePicker("Test", selection:$date).id(1)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: [=11=].frame(in: .local).size.height) })
}
.onPreferenceChange(ViewHeightKey.self) { self.height = [=11=] }
.modifier(AnimatingCellHeight(height: height))
.animation(.default)
// demo of simple solution
VStack {
DatePicker("Test", selection:$date).id(2)
}.animation(nil)
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date).datePickerStyle(WheelDatePickerStyle()).labelsHidden().id(3)
}
}
Section(header: Text("hello")) {
Text("test")
}
}
}
}
我在使用 SwiftUI 表单的 DatePickers 时遇到了一些奇怪的动画行为。一张图片值一千字,所以我敢肯定一个视频值一百万字:https://imgur.com/a/UHXqXOh
我试图让日期选择器在表单中展开然后折叠,就像在 Calendar.app
中创建新事件时的行为一样我的情况是:
- 部分中的任何展开项(最后一个除外)将正常打开,但当它关闭时,展开部分会向下滑动并淡出,而不是向上滑动并淡出。
- 该部分的最后一项滑动正确,但根本没有淡出。它只是在过渡 的 start/end 处出现然后消失
仅当表单中某处存在非 DatePicker 元素(例如文本、滑块)时才会发生这些行为(不必位于该特定部分)
这是我的内容视图:
struct ContentView: View {
@State var date = Date()
@State var isDateShown = false
var body: some View {
Form {
Section(header: Text("Title")) {
DatePicker("Test", selection:$date)
DatePicker("Test", selection:$date)
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date).datePickerStyle(WheelDatePickerStyle()).labelsHidden()
}
}
Section(header: Text("hello")) {
Text("test")
}
}
}
}
很乐意提供任何其他需要的东西
够有趣了..在新的测试版中,他们显然改变了 DatePicker。
所以如果您对 iOS 14+ 没问题...
最接近的解决方案是将日期选择器移动到它自己的部分
Form {
Section(header: Text("Title")) {
DatePicker(selection:$date1, label: {Text("Test")} )
}
DatePicker("Test", selection:$date2)
Section{
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date3).datePickerStyle(WheelDatePickerStyle()).labelsHidden()
}
}
Section(header: Text("Hello")){
Text("Hello")
}
}
对于 iOS <14,有两种可能的解决方法:1) 简单的一种是完全禁用动画,2) 复杂的一种是通过注入自定义动画修改器来减少不正确的动画
均使用 Xcode 11.4 / iOS 13.4
进行了测试1) 简单的解决方案 - 将DatePicker
包装到容器中并将动画设置为nil
VStack {
DatePicker("Test", selection:$date).id(2)
}.animation(nil)
2) 复杂的解决方案 - 使用 a) 从我的其他解决方案中查看偏好 reader DatePicker
更改框架。
struct TestDatePickersInForm: View {
@State var date = Date()
@State var isDateShown = false
@State private var height = CGFloat.zero
var body: some View {
Form {
Section(header: Text("Title")) {
// demo of complex solution
VStack {
DatePicker("Test", selection:$date).id(1)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: [=11=].frame(in: .local).size.height) })
}
.onPreferenceChange(ViewHeightKey.self) { self.height = [=11=] }
.modifier(AnimatingCellHeight(height: height))
.animation(.default)
// demo of simple solution
VStack {
DatePicker("Test", selection:$date).id(2)
}.animation(nil)
Text("Pick a date").onTapGesture {
withAnimation {
self.isDateShown.toggle()
}
}
if(isDateShown) {
DatePicker("", selection: $date).datePickerStyle(WheelDatePickerStyle()).labelsHidden().id(3)
}
}
Section(header: Text("hello")) {
Text("test")
}
}
}
}