我正在尝试制作一个将Blur()放在iPhone布局底部的视图,同时遵守安全区,并且我可以轻松地重用。
类似这样的东西:
import SwiftUI
struct SafeBottomBlurContainer: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
ZStack {
Blur(style: self.colorScheme == .dark ? .systemThinMaterialDark : .systemThinMaterialLight)
.frame(
width: geometry.size.width,
height: geometry.safeAreaInsets.bottom + 50
)
Holder()
.padding(.bottom, geometry.safeAreaInsets.bottom)
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
}
struct Holder: View {
var body: some View {
Rectangle().opacity(0.5)
.frame(height: 50)
}
}
struct SafeBottomBlurContainer_Previews: PreviewProvider {
static var previews: some View {
SafeBottomBlurContainer()
}
}
顺便说一下,这是~~ blue ~~模糊扩展名:
import SwiftUI
struct Blur: UIViewRepresentable {
var style: UIBlurEffect.Style = .systemMaterial
func makeUIView(context: Context) -> UIVisualEffectView {
return UIVisualEffectView(effect: UIBlurEffect(style: style))
}
func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
uiView.effect = UIBlurEffect(style: style)
}
}
现在,我想做的是以某种方式传入Holder()
,以便我可以调整“模糊”的高度(这里是+ 50)。我觉得我应该以某种方式使用AnyView,但无法弄清楚。可能是我走错了路。
这是我希望 在ContentView()示例中使用它的方式:
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.pink.edgesIgnoringSafeArea(.all)
SafeBottomBlurContainer(containedView: MyCustomViewWithWhateverHeight)
}
}
}
答案 0 :(得分:1)
这是一种可能的方法,它使使用像这样的容器成为可能
struct ContentView: View {
var body: some View {
ZStack {
Color.pink.edgesIgnoringSafeArea(.all)
// holder is not needed, because you can pass any view directly
SafeBottomBlurContainer(containedView: Text("Demo"))
}
}
}
和通用模糊容器
struct SafeBottomBlurContainer<V: View>: View {
@Environment(\.colorScheme) var colorScheme
var containedView: V
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
ZStack {
Blur(style: self.colorScheme == .dark ? .systemThinMaterialDark : .systemThinMaterialLight)
.frame(
width: geometry.size.width,
height: geometry.safeAreaInsets.bottom + 50
)
containedView
.padding(.bottom, geometry.safeAreaInsets.bottom)
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
}
答案 1 :(得分:0)
从@Asperi带领我真正走上正轨,现在,我有了这个想法,试图也适应这个Blur()
视图应该在屏幕的顶部还是底部:
import SwiftUI
struct SafeEdgesBlurContainer<V: View>: View {
@Environment(\.colorScheme) var colorScheme
@State var containedViewSize: CGSize = .zero
var containedView: V
var isPlacedAtTop: Bool
var body: some View {
GeometryReader { geometry in
VStack {
if !isPlacedAtTop {
Spacer()
}
ZStack {
Blur(style: self.colorScheme == .dark ? .systemThinMaterialDark : .systemThinMaterialLight)
.frame(
width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
height: (isPlacedAtTop ? geometry.safeAreaInsets.top : geometry.safeAreaInsets.bottom ) + containedViewSize.height
)
.edgesIgnoringSafeArea([.leading])
HStack {
ChildSizeReader(size: $containedViewSize) {
containedView
}
.frame(width: geometry.size.width) // ADDED This line to keep the ContainedView centered in Landscape
.padding(isPlacedAtTop ? .top : .bottom, isPlacedAtTop ? geometry.safeAreaInsets.top : geometry.safeAreaInsets.bottom)
}
}
if isPlacedAtTop {
Spacer()
}
}
.edgesIgnoringSafeArea(isPlacedAtTop ? .top : .bottom)
}
}
}
事实证明,获取ContainedView()的高度并不难。我从这里找到了这个解决方案:SwiftUI - Get size of child?
struct ChildSizeReader<Content: View>: View {
@Binding var size: CGSize
let content: () -> Content
var body: some View {
ZStack {
content()
.background(
GeometryReader { proxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
}
.onPreferenceChange(SizePreferenceKey.self) { preferences in
self.size = preferences
}
}
}
struct SizePreferenceKey: PreferenceKey {
typealias Value = CGSize
static var defaultValue: Value = .zero
static func reduce(value _: inout Value, nextValue: () -> Value) {
_ = nextValue()
}
}
我看到的剩下的问题是ContainedView()不在横向视图中居中。但希望我能很快回来并为此提供解决方案。
编辑:这可能是该解决方案:HStack上的.frame(width: geometry.size.width)
。