我为UIViewRepresentable
创建了一个UIVisualEffectView
,以使某些组件充满活力。这是可行的,但是似乎有时会垂直缩小控件,或者只是在运行时随意更改其边界。我似乎无法使其可靠运行。我需要它来处理任何SwiftUI内容或什至用于内容的其他UIViewRepresentable
。将UIVisualEffectView
包裹在UIView
内并使用自动布局似乎有所帮助,但是其他控件(例如包裹在UILabel
内的自定义UIViewRepresnetable
被垂直修剪)。
public struct VibrantView<Content: View>: UIViewRepresentable {
private let content: UIView!
private let vibrancyBlurEffectStyle: UIBlurEffect.Style
init(vibrancyBlurEffectStyle: UIBlurEffect.Style, @ViewBuilder content: () -> Content) {
self.content = UIHostingController(rootView: content()).view
self.vibrancyBlurEffectStyle = vibrancyBlurEffectStyle
}
public func makeUIView(context: Context) -> UIView {
let containerView = UIView()
let blurEffect = UIBlurEffect(style: vibrancyBlurEffectStyle)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
let blurView = UIVisualEffectView(effect: vibrancyEffect)
blurView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(blurView)
content.backgroundColor = .clear
content.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(content)
NSLayoutConstraint.activate([
blurView.widthAnchor.constraint(equalTo: containerView.widthAnchor),
blurView.heightAnchor.constraint(equalTo: containerView.heightAnchor),
content.widthAnchor.constraint(equalTo: blurView.widthAnchor),
content.heightAnchor.constraint(equalTo: blurView.heightAnchor),
])
content.setContentHuggingPriority(.defaultLow, for: .vertical)
content.setContentHuggingPriority(.defaultLow, for: .horizontal)
content.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
content.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)
blurView.setContentHuggingPriority(.defaultLow, for: .vertical)
blurView.setContentHuggingPriority(.defaultLow, for: .horizontal)
blurView.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
blurView.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)
return containerView
}
public func updateUIView(_ uiView: UIView, context: Context) {
}
}
用作:
...
VibrantView(vibrancyBlurEffectStyle: .dark) {
Text("Hello")
.foregroundColor(Color.gray)
}
在VStack
中带有其他视图的设备上运行时,您会看到“ Hello”从底部被部分裁剪。在“预览”中,您将在“ Hello”周围看到一个更大的蓝色矩形(边界),而我希望它包含内容。 VStack
不会假定整体视图的自然高度。
使用fixedSize()
不起作用,当与其他控件一起使用时,甚至会产生怪异的结果。
答案 0 :(得分:4)
尝试了各种技巧和技巧后-我根本无法使UIKit容器(即VibrantView
)可靠地拥抱其SwiftUI内容,而没有在顶部添加固定大小的.frame(...)
修饰符-这使其成为现实很难将其与动态调整大小的Text
一起使用。
对我有用的是一点技巧,可能无法在其中使用所有通用视图(并且可能无法很好地扩展数十个视图),但是对于简单的用例尤其适用,您将其托管在动态调整大小的UITableViewCell
中。
想法是使用同一视图的虚拟版本,并将VibrantView
设置为.overlay( ... )
。这将强制叠加层采用与父级SwitfUI View
相同的整体大小。由于要应用的视图修饰符是VibrantView
所包装的同一视图的副本,因此最终会在运行时和Xcode预览中获得正确的动态大小。
是这样的:
SomeView()
.frame(minWidth: 0, maxWidth: .infinity)
.overlay(
VibrantView(vibrancyBlurEffectStyle: .dark) {
SomeView()
.frame(minWidth: 0, maxWidth: .infinity)
}
)
我可以想象将其变成一个修饰符,以便在一次调用中将以上内容包装起来,但是在我的情况下,为确保它对Images仍然有效,我正在执行以下操作:
Circle()
.foregroundColor(.clear)
.frame(width: 33, height: 33)
.overlay(
VibrantView(vibrancyBlurEffectStyle: .systemMaterialDark) {
Image("some image")
.resizable()
}
)
与实际图像相比,创建Circle
的重量可以说更轻。我创建一个透明的圆圈,在此处设置图像的实际大小,然后将VibrantView
容器放入overlay
。
答案 1 :(得分:0)
为什么这么复杂?
尝试一下:
struct Blur: UIViewRepresentable {
#if os(iOS)
var style: UIBlurEffect.Style = .systemMaterial
#else
var style: UIBlurEffect.Style = .light
#endif
init(_ style: UIBlurEffect.Style = .dark) {
self.style = style
}
func makeUIView(context: Context) -> UIVisualEffectView {
return UIVisualEffectView(effect: UIBlurEffect(style: style))
}
func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
uiView.effect = UIBlurEffect(style: style)
}
}
并使用:
Text("Great text with prominent")
.font(.largeTitle)
.padding()
.background(Blur(.prominent))
通常,您不应该在UIViewRepresentable中使用约束->大小将由父视图(如本示例中的Text或VStack)定义,该父视图为模糊提供了正确的大小。通常,模糊并不是一个独立的背景,而是典型的模糊背景,因为您想在上面放上文字,以便更好地阅读文字。