Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
swiftUI中旋转动画的性能不佳_Swift_Performance_Animation_Swiftui - Fatal编程技术网

swiftUI中旋转动画的性能不佳

swiftUI中旋转动画的性能不佳,swift,performance,animation,swiftui,Swift,Performance,Animation,Swiftui,我用swiftUI创建了一个指南针应用程序,一切正常,但是可以对指南针旋转的动画进行一些改进。我重新创建了一个只有指南针的项目,用代码来说明这一点。在这个版本中,不会报告任何性能问题,因为只有罗盘可以计算。但是在我的实际应用程序中,如果有更多的元素,性能就不是最优的 简易指南针应用程序代码: (出于技术原因,我必须将UIKit与CGAffineTransform一起使用,以矩阵旋转为指南针旋转设置动画,以避免产生不必要的效果) 位置提供程序: import SwiftUI import UIKi

我用swiftUI创建了一个指南针应用程序,一切正常,但是可以对指南针旋转的动画进行一些改进。我重新创建了一个只有指南针的项目,用代码来说明这一点。在这个版本中,不会报告任何性能问题,因为只有罗盘可以计算。但是在我的实际应用程序中,如果有更多的元素,性能就不是最优的

简易指南针应用程序代码:

(出于技术原因,我必须将
UIKit
CGAffineTransform
一起使用,以矩阵旋转为指南针旋转设置动画,以避免产生不必要的效果)

位置提供程序:

import SwiftUI
import UIKit
import CoreLocation
import Combine

public class LocationProvider: NSObject, CLLocationManagerDelegate, ObservableObject {
  
  private let locationManager: CLLocationManager
  
  public let heading = PassthroughSubject<Double, Never>()
  
  @Published var currentHeading: Double {
    willSet {
      heading.send(newValue)
    }
  }
  
  public override init() {
    currentHeading = 0
    locationManager = CLLocationManager()
    
    super.init()
    
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingHeading()
  }
  
  public func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
    self.currentHeading = newHeading.magneticHeading
  }
}
导入快捷界面
导入UIKit
导入核心定位
进口联合收割机
公共类LocationProvider:NSObject、CLLocationManagerDelegate、ObservableObject{
私人出租位置管理器:CLLocationManager
公共let heading=PassthroughSubject()
@当前标题:双{
意志{
标题.发送(newValue)
}
}
公共重写init(){
当前航向=0
locationManager=CLLocationManager()
super.init()
locationManager.delegate=self
locationManager.desiredAccuracy=KCallocationAccuracyBest
locationManager.startUpdatingHeading()
}
公共函数位置管理器(u管理器:CLLocationManager,didUpdateHeading新标题:CLHeading){
self.currentHeading=newHeading.magneticeHeading
}
}
罗盘视图:

import SwiftUI
import UIKit
import CoreLocation

public extension CGFloat {
  var degreesToRadians: CGFloat { return self * .pi / 180 }
}

struct ContentView: View {
    
  @ObservedObject var location: LocationProvider = LocationProvider()
      
  private var windowWidth: CGFloat = UIScreen.main.bounds.width
  
  @State private var heading: CGFloat = .zero
  
  // Arrow view
  struct ArrowView: UIViewRepresentable {
    var angle: CGFloat
    var width: CGFloat
    var height: CGFloat
    var container: UIView = UIView()
    var imageView: UIImageView = UIImageView()
    var imageName: String
    
    func makeUIView(context: Context) -> some UIView {
      
      // Container
      container.frame = CGRect.init(
        x: 0,
        y: 0,
        width: height < width ? height : width,
        height: height < width ? height : width
      )
      container.isOpaque = true
      
      // Image
      imageView.image = UIImage(named: imageName)
      imageView.frame = CGRect.init(
        x: height < width ? 0 : 20,
        y: height < width ? 0 : 20,
        width: height < width ? height : width - 40,
        height: height < width ? height : width - 40
      )
      imageView.isOpaque = true
      
      container.addSubview(imageView)
      
      return container
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
      UIView.animate(withDuration: 0.2, delay: 0, options: UIView.AnimationOptions.curveEaseIn, animations: {
        uiView.subviews[0].transform = CGAffineTransform(rotationAngle: -angle.degreesToRadians)
      }, completion: nil)
      
      // Mise à jour de l'image
      let imageView = uiView.subviews.compactMap{ $0 as? UIImageView }
      imageView[0].image = UIImage(named: imageName)
    }
  }
  
  var body: some View {
    VStack {
      ArrowView(angle: self.heading, width: self.windowWidth - 20, height: self.windowWidth - 20, imageName: "arrow")
        .frame(width: self.windowWidth, height: self.windowWidth, alignment: .center)
    }
    .onReceive(self.location.heading) { heading in
      self.heading = CGFloat(heading)
    }
  }
}
导入快捷界面
导入UIKit
导入核心定位
公共扩展CGFloat{
变量度弧度:CGFloat{return self*.pi/180}
}
结构ContentView:View{
@ObservedObject变量位置:LocationProvider=LocationProvider()
私有变量windowWidth:CGFloat=UIScreen.main.bounds.width
@国家私有变量标题:CGFloat=.0
//箭头视图
结构ArrowView:UIViewRepresentable{
变量角度:CGFloat
变量宽度:CGFloat
变量高度:CGFloat
变量容器:UIView=UIView()
var-imageView:UIImageView=UIImageView()
var-imageName:String
func makeUIView(context:context)->一些UIView{
//容器
container.frame=CGRect.init(
x:0,,
y:0,
宽度:高度<宽度?高度:宽度,
高度:高度<宽度?高度:宽度
)
container.isOpaque=true
//形象
imageView.image=UIImage(名称:imageName)
imageView.frame=CGRect.init(
x:高度<宽度?0:20,
y:高度<宽度?0:20,
宽度:高度<宽度?高度:宽度-40,
高度:高度<宽度?高度:宽度-40
)
imageView.isOpaque=true
container.addSubview(imageView)
返回容器
}
func updateUIView(uiView:UIViewType,context:context){
UIView.animate(持续时间:0.2,延迟:0,选项:UIView.AnimationOptions.curveEaseIn,动画:{
uiView.subviews[0]。transform=CGAffineTransform(旋转角度:-角度.度数弧度)
},完成日期:无)
//你的形象如何
让imageView=uiView.subviews.compactMap{$0 as?UIImageView}
imageView[0]。image=UIImage(名称:imageName)
}
}
var body:一些观点{
VStack{
箭头视图(角度:self.heading,宽度:self.windowWidth-20,高度:self.windowWidth-20,图像名称:“箭头”)
.frame(宽度:self.windowWidth,高度:self.windowWidth,对齐:。中心)
}
.onReceive(self.location.heading){heading in
self.heading=CGFloat(heading)
}
}
}
我已经寻找了几种方法来解决这个问题,但我不确定最好的方法是什么

  • 将代码分成一个子组件
  • 使用SpriteKit制作指南针动画
  • 我读到一种方法,可以在主线程之外执行一些任务

每次SwiftUI由于标题更改而使视图无效时,您都在创建该视图。如果不分析它,我不能百分之百确定,但这是我首先想到的

两种选择:

第一种方法是将绘图代码转换为SwiftUI native,如果只是旋转预定义的图像,则使用路径和形状或图像。然后利用旋转的杠杆。SwiftUI在缓存不需要更改的图像时会更加积极,因为您只对它们应用旋转

第二个是在SwiftUI视图中应用旋转,这将为您缓存底层UIView渲染-这意味着将旋转和动画移动到SwiftUI中。您提到了一个不必要的影响,它导致您使用CGAffineTransform,但在该级别进行旋转的结果是,每次更新时,您都会将该图像分插到新构建的视图中,这非常昂贵

我建议您使用SwiftUI的视图,如果您想要定制线路,并且用于重载。在玩联合收割机时,我自己也做了类似的事情,结果非常有效,性能也很好