SwiftUI-在当前视图内为新图像设置动画

时间:2020-04-04 18:00:45

标签: swiftui

我有一个View,在其中我使用Picture(图像)子视图显示图像,该图像可以具有不同的高度和宽度格式。

对图像的引用是从数组中提取的,这使我可以通过更改引用在视图中显示不同的图像。 SwiftUI重新排列每个新图像的视图内容

我想在显示图像时在此图像上显示动画,例如缩放效果

1)我需要第一个.animation(nil)来避免对前一个图像进行动画处理(否则,我会出现难看的淡出效果和长宽比变形)。似乎是很好的解决方法

2)但是,我的scaleEffect修饰符有一个问题(即使我将其设置为scale = 1,它也不应该执行任何操作) 动画通过强加图像2的左上角从图像1的左上角开始而从图像1移动到图像2,该宽度和高度不同,会引起图像中心的不必要平移
这在下面的代码中进行了复制,出于演示目的,我正在使用系统映像(不容易出现错误1)

如何避免这种情况?

3)在下面的演示代码中,我使用一个按钮触发了新图像,这使我可以使用动作并处理“缩放”修改,并明确实现所需的效果。但是在我的真实代码中,图像修改是由另一个视图中的另一个更改触发的。

Swift知道这一点,因此我可以使用隐式的.animation修饰符。

但是,我不知道如何对任何新图像施加“比例”重置并达到我想要的效果。

  • 如果我使用onAppear(我的代码),则仅适用于显示的第一个图像,而不适用于随后的图像。

  • 在真实代码中,我有一个Picture(图像)视图,而Picture(image.animation())无法编译。

有什么想法如何在隐式动画的Button中实现以下代码中的操作?

谢谢

import SwiftUI

let portrait = Image(systemName: "square.fill")
let landscape = Image(systemName: "square.fill")

struct ContentView: View {
    @State var modified = false
    @State var scale: CGFloat = 1

var body: some View {
    return VStack(alignment: .center) {

        Pictureclip(bool: $modified)  
            .animation(nil)
            .scaleEffect(scale)
            .animation(.easeInOut(duration: 1))

       Button(action: {
        self.modified.toggle()
        self.scale = 1.1
        DispatchQueue.main.asyncAfter(deadline: .now() + 1)
            {self.scale = 1}
        }) {
            Text("Tap here")
                .animation(.linear)
        }            
     }
}
}
struct Pictureclip: View {

  @Binding var bool: Bool

  var body: some View {
  if bool == true {
    return  portrait
        .resizable()
        .frame(width: 100, height: 150)
        .foregroundColor(.green)
  } else {
   return  landscape
        .resizable()
        .frame(width: 150, height: 100)
        .foregroundColor(.red)
    }
    }
}

2 个答案:

答案 0 :(得分:0)

我对问题有一个半答案,即第1点和第2点(此处参考资产目录中的两个jpeg图像)

import SwiftUI
let portrait = Image("head")
let landscape = Image("sea")

struct ContentView: View {
    @State var modified = false
    @State var scale: CGFloat = 0.95


var body: some View {
    VStack(){

    GeometryReader { geo in
        VStack {
            Picture(bool: self.modified)
                .frame(width: geo.size.width * self.scale)
        }
        }
      Spacer()
      Button(action: {
                self.scale = 0.95
                self.modified.toggle()

        withAnimation(.easeInOut(duration: 0.5)){
                    self.scale = 1

                }
      }) {
                Text("Tap here")
          }
    }
}
}
struct Picture: View {
    var bool: Bool
var body: some View {
if bool == true {
    return  portrait
        .resizable().aspectRatio(contentMode: .fit)
        .padding(.all,6.0)
} else {
   return  landscape
        .resizable().aspectRatio(contentMode: .fit)
        .padding(.all,6.0)
}
}
}

此解决方案可实现缩放,而不会在动画过程中扭曲新图像的纵横比。但是,它不适用于在另一个视图中触发图像更新的代码。我想我必须重组我的代码,以解决问题或更清楚地揭示它。

编辑:一种快速而肮脏的解决方案是将触发代码(此处为按钮中的操作代码)放在另一个视图中。即,将传递视图状态动画的代码(传递给它的状态变量)放入视图B中(此处为“缩放”)。我敢肯定有更清洁的方法,但是至少这是可行的。

答案 1 :(得分:0)

我不确定,但也许对你有帮助。 使用数据绑定结构。我是这样用的:

let binding = Binding<String>(get: {
            self.storage
        }, set: { newValue in
            self.textOfPrimeNumber = ""
            self.storage = newValue
            let _ = primeFactorization(n: Int(self.storage)!, k: 2, changeable: &self.textOfPrimeNumber)
        })