在SwiftUI中,如何高性能地绘制阴影?

8yoxcaq7  于 2022-12-10  发布在  Swift
关注(0)|答案(2)|浏览(185)

我使用.shadow(color:, radius:, x:, y:)在我的应用程序中绘制阴影。这是我所知道的SwiftUI中绘制应用程序的唯一方法。我使用.sheet(isPresented:, content:)方法弹出一个视图,其中包含大量阴影,当我调试视图层次结构时,我看到了以下警告:

但我不知道如何设置shadowPath,或预先渲染的阴影到一个图像,并把它放在层下的SwiftUI,请帮助我。

ej83mcc0

ej83mcc01#

This warning is not caused because your code is inherently bad, but as a way of telling you that there are much more performant ways of rendering shadows.
As your UI elements are currently written, SwiftUI is drawing the shadows around your view objects dynamically (at Runtime) based on wherever their positions and bounds are at the time, and that rendering will follow the view throughout it's lifecycle.
It's a math intensive process and involves many draw-calls to the GPU in the best of cases, and CPU bottlenecking as well in the worst of cases.
There are several different ways of rendering shadows in Swift. Most of them utilize frameworks OUTSIDE of SwiftUI (UIKit and CoreGraphics, usually, though Metal, Core Animation, and Core Image have been important in various applications.)
This warning is probably not a big deal if you're not seeing performance problems in the UI layer on target hardware, but if you're very motivated to solve the problem, there are some options:

Option 1

The absolute easiest thing to do if you just want to make the error go away would be to force a GPU call rasterization for the view + shadow by adding

.drawingGroup()

somewhere after the .shadow view. Be advised, this will likely look like crap compared to dynamic shadows. If you're familiar with UIKit, this is similar to the layer.shouldRasterize property on UIView.

Option 2

Speaking of UIKit, an alternative would be to head over there and use either a UIViewRepresentable of your SwiftUI drawing logic, or a completely separate UIView. Either way:

myView = UIView()
myView.layer.shadowPath = UIBezierPath(rect: myView.bounds.cgPath)

should get you started... the other shadow properties and stuff will help.

Option 3

You could render the shadow as an image, either programatically (hard) or in an imaging editing application (annoying) and load is as an image at a lower Z index than your view, and scale them to give the illusion of depth.
This is the kind of hacky work around that game developers used to do when they had crappy hardware but still wanted things to look good.
In the end... for MOST SwiftUI views this warning likely can be ignored. If you load the code in Instruments, you'll likely see that the dynamic rendering of drop shadows under a View is probably not impacting your view rendering performance significantly. This warning is only usually visible inside a UI Debug session.
Hope this helps set you on the path to a solution.

3pvhb19x

3pvhb19x2#

这周我遇到了这个问题。我想我找到了一种方法,它的性能和UIKit中的shadowPath选项一样好。我 * 认为 * 当你使用Shape().shadow(...)时,它会根据路径绘制一个有效的阴影。所以如果你知道你要给它一个阴影的东西的形状,你可以这样做:

content
  // Use background so the shadow is the same size as the content
  .background(
    // I'm assuming rectangle but it can be anything like with rounded corners too
    Rectangle()
      // Add efficient shadow
      .shadow()
      // Add an inset so you don't see the ugly inner edge of the shadow, it will be under your content
      .padding(1)
  )

这比我之前的速度快多了!

相关问题