我有一个相当简单的视图,背景图像和选择器。我想根据当前选定的值更改背景图像。下面的代码可以工作,但是图像更改的动画缺少了--知道为什么吗?
@State private var pickerIndex = 0
@State private var currentBackgroundImage = "fitness-1"
var body: some View {
ZStack {
Image(currentBackgroundImage)
.resizable()
.aspectRatio(contentMode: .fill)
.transition(.opacity)
.edgesIgnoringSafeArea(.all)
VStack(spacing: 20) {
Picker(selection: $pickerIndex, label: Text("")) {
Image("img1")
.tag(0)
Image("img2")
.tag(1)
}
.onChange(of: genderPickerIndex, perform: { value in
if(value == 0) {
withAnimation {
currentBackgroundImage = "fitness-1"
}
} else {
withAnimation {
currentBackgroundImage = "fitness-2"
}
}
})
.frame(width: 100)
.pickerStyle(SegmentedPickerStyle())
}
}
}
编辑:
它似乎与选择无关-我只是用一个按钮替换它,图像变化仍然没有动画。我是不是在图像上少了一些修饰符?
ZStack {
Image(currentBackgroundImage)
.resizable()
.aspectRatio(contentMode: .fill)
.transition(.opacity)
.edgesIgnoringSafeArea(.all)
Button(action: {
withAnimation {
currentBackgroundImage = "fitness-2"
}
}) {
Text("Change Image")
}
}
发布于 2021-03-07 08:11:53
好的,为了获得我想要的动画,我创建了一个额外的组件:
struct ImageSwitcher: View {
let firstImage: String
let secondImage: String
@Binding var firstImageShowing: Bool
var body: some View {
ZStack {
Image(firstImage)
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.opacity(firstImageShowing ? 1 : 0)
.transition(.move(edge: .trailing))
.animation(.easeInOut(duration: 0.17))
.isHidden(!firstImageShowing)
Image(secondImage)
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.opacity(firstImageShowing ? 0 : 1)
.transition(.move(edge: .leading))
.isHidden(firstImageShowing)
.animation(.easeInOut(duration: 0.17))
}
}
}
.isHidden修饰符是一个扩展,用于根据状态变量隐藏图像。您可以在本文中看到更多详细信息:Dynamically hiding view in SwiftUI
很明显,您可以修改转换,但是我最终使用转换和不透明修饰符进行移动和淡入/淡出。
用法:
创建状态变量:
@State private var showFirst = true
然后将它连同图像名称一起交给组件:
ImageSwitcher(firstImage: "img-1", secondImage: "img-2", firstImageShowing: $showFirst)
发布于 2021-03-05 07:41:53
选择器选择的类型为String
,选择器数据的类型为Text
,因此不会调用onChange
修饰符。选择器选择类型和content
类型必须相同,链接Picker in SwiftUI works with one version of ForEach, but not the other - a bug, or expected behavior?中的@Asperi也解释了这一点。相反,您可以使用forEach
并循环您的[string]
名称。
struct ContentViewsss:View{
var images = ["ABC","CDF"]
@State private var pickerValue = "ABC"
@State private var currentBackgroundImage = "ABC"
var body: some View {
VStack {
Image(currentBackgroundImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 150)
.clipShape(Circle())
.edgesIgnoringSafeArea(.all)
.transition(.opacity)
Picker(selection: $pickerValue, label: Text("")) {
ForEach(images,id:\.self) { imageName in
Text("\(imageName)")
}
}
.onChange(of: pickerValue, perform: { value in
self.changeBackgroundImage(value)
})
.frame(width: 200)
.pickerStyle(SegmentedPickerStyle())
}
}
func changeBackgroundImage(_ value: String) {
switch value {
case "ABC":
withAnimation {
currentBackgroundImage = "ABC"
}//the app changes the image, but the "withAnimation" does not seem to do anything
case "CDF":
withAnimation {
currentBackgroundImage = "CDF"
}//the app changes the image, but the "withAnimation" does not seem to do anything
default:
currentBackgroundImage = "landing-page"
}
}
}
或者您可以在newValue
内部直接分配onChange
,而不是单独的函数。
struct ContentViewsss:View{
var images = ["ABC","CDF"]
@State private var pickerValue = "ABC"
@State private var currentBackgroundImage = "ABC"
var body: some View {
VStack {
Image(currentBackgroundImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 150)
.clipShape(Circle())
.edgesIgnoringSafeArea(.all)
.transition(.opacity)
Picker(selection: $pickerValue, label: Text("")) {
ForEach(images,id:\.self) { imageName in
Text("\(imageName)")
}
}
.onChange(of: pickerValue, perform: { value in
withAnimation {
currentBackgroundImage = value
}
//self.changeBackgroundImage(value)
})
.frame(width: 200)
.pickerStyle(SegmentedPickerStyle())
}
}
}
https://stackoverflow.com/questions/66487867
复制相似问题