1

I put on an image and it fills widget view.

And I made small view and wanted this view shows blurred imaged of behind image.

(image and small view are in the ZStack)

I used few code (something like Option 2 from Is there a method to blur a background in SwiftUI?)

but the result is like

enter image description here

I think that yellow box means 'VisualEffectView doesn't work in WidgetKit.'

So I wonder if there is other technique to show small view that shows blurred behind image?

pawello2222
  • 46,897
  • 22
  • 145
  • 209
WoffOVkee
  • 435
  • 3
  • 16

2 Answers2

0

I think that yellow box means 'VisualEffectView doesn't work in WidgetKit.'

Yes, specifically because you can't use UIViewRepresentable in Widgets. See:

It means that the only option is to use SwiftUI code. A possible solution is here (Option 1):

struct WidgetEntryView: View {
    var entry: Provider.Entry

    var body: some View {
        ZStack {
            Image("testImage")
                .blur(radius: 10)
        }
        .edgesIgnoringSafeArea(.all)
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
0

I found some workaround

first, i put the original picture

then put a picture which applied Gaussian filter on the original picture

and add clipShape to the filtered image.

object for argument of clipShape needs to confirm Shape protocol like

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

and I found Gaussian filter code from

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

pseudo code

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(...))
    }
}

then you will get something like this enter image description here

Update

looks like widget has kind of memory limit

if you run this code on real device it can be crashed (most time simulator works find, in my case)

you can resolve this problem through adjusting radius value of applyBlur_usingClamp method. (250 crashed, 100 is fine for me)

WoffOVkee
  • 435
  • 3
  • 16