【问题标题】:UIVisualEffectView does not work in iOS 14 WidgetUIVisualEffectView 在 iOS 14 小部件中不起作用
【发布时间】:2020-11-05 08:59:08
【问题描述】:

我放了一张图片,它会填满小部件视图。

我做了一个小视图,希望这个视图显示背后图像的模糊图像。

(图像和小视图在 ZStack 中)

我使用的代码很少(类似于Is there a method to blur a background in SwiftUI? 中的选项 2)

但结果是这样的

我认为黄色框表示“VisualEffectView 在 WidgetKit 中不起作用。”

所以我想知道是否有其他技术可以显示在图像后面显示模糊的小视图?

【问题讨论】:

    标签: swiftui ios14 uivisualeffectview widgetkit


    【解决方案1】:

    我认为黄色框表示“VisualEffectView 不起作用 WidgetKit。'

    是的,特别是因为您不能在小部件中使用UIViewRepresentable。见:

    这意味着唯一的选择是使用 SwiftUI 代码。这里有一个可能的解决方案(选项 1):

    struct WidgetEntryView: View {
        var entry: Provider.Entry
    
        var body: some View {
            ZStack {
                Image("testImage")
                    .blur(radius: 10)
            }
            .edgesIgnoringSafeArea(.all)
        }
    }
    

    【讨论】:

      【解决方案2】:

      我找到了一些解决方法

      首先,我放原图

      然后在原图上放一张应用高斯滤波的图片

      并将 clipShape 添加到过滤后的图像。

      clipShape 参数的对象需要像这样确认 Shape 协议

      struct MyShape: Shape {
        func path(in rect: CGRect) -> Path {
          RoundedRectangle(cornerRadius: 10.0).path(...)
        }
      }
      

      我从

      中找到了高斯滤波器代码

      https://gist.github.com/Zedd0202/8d3e567161d0c92e7d585bb74e926413#file-applyblur_usingclamp-swift

      伪代码

      ZStack {
        Image("image")
        Image("image")
          .clipShape(YourShape())
          .frame(...)
          .padding(...)
      }
      ---
      extension UIImage {
        func applyBlur_usingClamp(radius: CGFloat) -> UIImage {
              let context = CIContext()
              guard let ciImage = CIImage(image: self),
                    let clampFilter = CIFilter(name: "CIAffineClamp"),
                    let blurFilter = CIFilter(name: "CIGaussianBlur") else {
                  return self
              }
              
              clampFilter.setValue(ciImage, forKey: kCIInputImageKey)
              
              blurFilter.setValue(clampFilter.outputImage, forKey: kCIInputImageKey)
              blurFilter.setValue(radius, forKey: kCIInputRadiusKey)
              guard let output = blurFilter.outputImage,
                    let cgimg = context.createCGImage(output, from: ciImage.extent) else {
                  return self
              }
              return UIImage(cgImage: cgimg)
          }
      }
      ---
      struct YourShape: Shape {
      
          
          func path(in rect: CGRect) -> Path {
              RoundedRectangle(cornerRadius: 10.0)
                  .path(in: CGRect(...))
          }
      }
      

      然后你会得到这样的东西

      更新

      看起来小部件有某种内存限制

      如果您在真实设备上运行此代码,它可能会崩溃(在我的情况下,大多数时候模拟器都可以工作)

      你可以通过调整applyBlur_usingClamp方法的半径值来解决这个问题。 (250 崩溃,100 对我来说没问题)

      【讨论】: