113 lines
3.6 KiB
Swift
113 lines
3.6 KiB
Swift
/*
|
||
See LICENSE folder for this sample’s licensing information.
|
||
|
||
Abstract:
|
||
The iOS implementation of a UIVisualEffectView's blur and vibrancy.
|
||
*/
|
||
|
||
import SwiftUI
|
||
|
||
// MARK: - VisualEffectBlur
|
||
|
||
struct VisualEffectBlur<Content: View>: View {
|
||
var blurStyle: UIBlurEffect.Style
|
||
var vibrancyStyle: UIVibrancyEffectStyle?
|
||
var content: Content
|
||
|
||
init(blurStyle: UIBlurEffect.Style = .systemMaterial, vibrancyStyle: UIVibrancyEffectStyle? = nil, @ViewBuilder content: () -> Content) {
|
||
self.blurStyle = blurStyle
|
||
self.vibrancyStyle = vibrancyStyle
|
||
self.content = content()
|
||
}
|
||
|
||
var body: some View {
|
||
Representable(blurStyle: blurStyle, vibrancyStyle: vibrancyStyle, content: ZStack { content })
|
||
.accessibility(hidden: Content.self == EmptyView.self)
|
||
}
|
||
}
|
||
|
||
// MARK: - Representable
|
||
|
||
extension VisualEffectBlur {
|
||
struct Representable<Content: View>: UIViewRepresentable {
|
||
var blurStyle: UIBlurEffect.Style
|
||
var vibrancyStyle: UIVibrancyEffectStyle?
|
||
var content: Content
|
||
|
||
func makeUIView(context: Context) -> UIVisualEffectView {
|
||
context.coordinator.blurView
|
||
}
|
||
|
||
func updateUIView(_ view: UIVisualEffectView, context: Context) {
|
||
context.coordinator.update(content: content, blurStyle: blurStyle, vibrancyStyle: vibrancyStyle)
|
||
}
|
||
|
||
func makeCoordinator() -> Coordinator {
|
||
Coordinator(content: content)
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Coordinator
|
||
|
||
extension VisualEffectBlur.Representable {
|
||
class Coordinator {
|
||
let blurView = UIVisualEffectView()
|
||
let vibrancyView = UIVisualEffectView()
|
||
let hostingController: UIHostingController<Content>
|
||
|
||
init(content: Content) {
|
||
hostingController = UIHostingController(rootView: content)
|
||
hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||
hostingController.view.backgroundColor = nil
|
||
blurView.contentView.addSubview(vibrancyView)
|
||
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||
vibrancyView.contentView.addSubview(hostingController.view)
|
||
vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||
}
|
||
|
||
func update(content: Content, blurStyle: UIBlurEffect.Style, vibrancyStyle: UIVibrancyEffectStyle?) {
|
||
hostingController.rootView = content
|
||
let blurEffect = UIBlurEffect(style: blurStyle)
|
||
blurView.effect = blurEffect
|
||
if let vibrancyStyle = vibrancyStyle {
|
||
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyStyle)
|
||
} else {
|
||
vibrancyView.effect = nil
|
||
}
|
||
hostingController.view.setNeedsDisplay()
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Content-less Initializer
|
||
|
||
extension VisualEffectBlur where Content == EmptyView {
|
||
init(blurStyle: UIBlurEffect.Style = .systemMaterial) {
|
||
self.init( blurStyle: blurStyle, vibrancyStyle: nil) {
|
||
EmptyView()
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Previews
|
||
|
||
struct VisualEffectBlur_Previews: PreviewProvider {
|
||
static var previews: some View {
|
||
ZStack {
|
||
LinearGradient(
|
||
gradient: Gradient(colors: [.red, .blue]),
|
||
startPoint: .topLeading,
|
||
endPoint: .bottomTrailing
|
||
)
|
||
|
||
VisualEffectBlur(blurStyle: .systemUltraThinMaterial, vibrancyStyle: .fill) {
|
||
Text("Hello World!")
|
||
.frame(width: 200, height: 100)
|
||
}
|
||
}
|
||
.previewLayout(.sizeThatFits)
|
||
}
|
||
}
|
||
|