ScrollView 影响 Geometry Reader 内的视图

问题描述 投票:0回答:1

主要内容查看:

struct ContentView: View {
    
    @State var editing: Bool = false
    @State var inputText: String = ""
    @State var vOffset: CGFloat = 0
    @State var hOffset: CGFloat = 0
    @State private var activeField: Int = 0
    
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                ZStack(alignment: .top) {
                    if activeField == 1 {
                        SuggestionTextFieldMenu(editing: $editing, text: $inputText)
                            .zIndex(1)
                            .offset(y: geometry.size.height * 0.57 - 70)
                    }
                    
                    TextField("Placeholder", text: $inputText, onEditingChanged: { edit in
                        self.editing = edit
                        self.activeField = 1
                    })
                    .padding(.horizontal, 10)
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50, alignment: .center)
                    .background(Color.init(red: 0.98, green: 0.98, blue: 0.98))
                    .cornerRadius(14)
                    .shadow(radius: 4)
                    .padding(.horizontal, 20)
                    .offset(y: geometry.size.height * 0.5 - 70)
                    
                    if activeField == 2 {
                        SuggestionTextFieldMenu(editing: $editing, text: $inputText)
                            .zIndex(1)
                            .offset(y: geometry.size.height * 0.5)
                    }
                    
                    TextField("Placeholder", text: $inputText, onEditingChanged: { edit in
                        self.editing = edit
                        self.activeField = 2
                    })
                    .padding(.horizontal, 10)
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50, alignment: .center)
                    .background(Color.init(red: 0.98, green: 0.98, blue: 0.98))
                    .cornerRadius(14)
                    .shadow(radius: 4)
                    .padding(.horizontal, 20)
                    .offset(y: geometry.size.height * 0.5)
                }
            }
        }
    }
}

import SwiftUI
public struct SuggestionTextFieldMenu: View {
    
    @State var names: [String] = ["Apple","Peach","Orange","Banana", "Melon", "Watermelon","Mandarin","Mulberries","Lemon","Lime","Loquat","Longan","Lychee","Grape","Pear","Kiwi","Mango"]
    @Binding var editing: Bool
    @Binding var inputText: String
    
    private var filteredTexts: Binding<[String]> { Binding (
        get: {
            return inputText.isEmpty ? names : names.filter { $0.contains(inputText) }
        },
        set: { _ in })
    }
    
    public init(editing: Binding<Bool>, text: Binding<String>) {
        self._editing = editing
        self._inputText = text
    }
    
    public init(editing: Binding<Bool>, text: Binding<String>, verticalOffset: CGFloat, horizontalOffset: CGFloat) {
        self._editing = editing
        self._inputText = text
    }
    
    public var body: some View {
        ScrollView {
            LazyVStack(spacing: 0) {
                ForEach(filteredTexts.wrappedValue, id: \.self) { textSearched in
                    
                    Text(textSearched)
                        .padding(.horizontal, 25)
                        .padding(.vertical, 25)
                        .frame(minWidth: 0,
                               maxWidth: .infinity,
                               minHeight: 0,
                               maxHeight: 50,
                               alignment: .leading)
                        .contentShape(Rectangle())
                        .onTapGesture(perform: {
                            inputText = textSearched
                            editing = false
                            self.endTextEditing()
                        })
                    Divider()
                        .padding(.horizontal, 10)
                }
            }
        }.background(Color.white)
        
        .cornerRadius(15)
        .foregroundColor(Color(.black))
        .ignoresSafeArea()
        .frame(maxWidth: .infinity,
               minHeight: 0,
               maxHeight: 50 * CGFloat( (filteredTexts.wrappedValue.count > 3 ? 3: filteredTexts.wrappedValue.count)))
        .shadow(radius: 4)
        .padding(.horizontal, 25)
        .isHidden(!editing, remove: !editing)
        
    }
}

import SwiftUI
public extension View {
    @ViewBuilder func isHidden(_ hidden: Bool, remove: Bool = false) -> some View {
        if hidden {
            if !remove {
                self.hidden()
            }
        } else {
            self
        }
    }
    
    func endTextEditing() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
                                        to: nil, from: nil, for: nil)
    }
}

@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public struct StatefulPreviewWrapper<Value, Content: View>: View {
    @State var value: Value
    var content: (Binding<Value>) -> Content

    public var body: some View {
        content($value)
    }

    public init(_ value: Value, content: @escaping (Binding<Value>) -> Content) {
        self._value = State(wrappedValue: value)
        self.content = content
    }
}

我厌倦了使用 vstack,但是当下拉菜单出现时,它会将元素向下推。我无法使用 Overlay,因为 IOS 14.0 不支持 Overlay。我改变 ScrollView 的位置确实改变了任何事情。现在我什至无法点击我的文本字段。当我单击文本字段时,我想在文本字段正下方显示下拉菜单,并且下拉菜单应该位于视图上方,并且不会更改体内其他视图的位置。

Current View of app with this code

swiftui drop-down-menu scrollview vstack swiftui-zstack
1个回答
0
投票

正如评论中提到的,您可以在 iOS 14 中使用叠加层,但语法略有不同。但是,由于建议菜单比它所显示的

TextField
高,因此使用
ZStack
并不是一个坏主意。

我建议的最大改变是使用偏移进行布局。相反,请使用填充。

您似乎正在使用

GeometryReader
来根据总显示高度的一小部分来定义视图的位置。这可能不是在不同尺寸的显示器上获得一致布局的非常可靠的方法。但如果你真的想这样做,你可以根据多余的高度对
ScrollView
应用填充。

这是您的

ContentView
身体的更新版本。建议图层显示在其他图层下方,这样就无需应用
.zIndex
。填充用于相对于
ZStack
的顶部定位视图。我省略了
GeometryReader
,因为我没有看到它有任何有用的目的。

var body: some View {
    ScrollView {
        ZStack(alignment: .top) {
            TextField("Placeholder", text: $inputText, onEditingChanged: { edit in
                self.editing = edit
                self.activeField = 1
            })
            .padding(.horizontal, 10)
            .frame(maxWidth: .infinity)
            .background(Color.init(red: 0.98, green: 0.98, blue: 0.98))
            .cornerRadius(14)
            .shadow(radius: 4)

            TextField("Placeholder", text: $inputText, onEditingChanged: { edit in
                self.editing = edit
                self.activeField = 2
            })
            .padding(.horizontal, 10)
            .frame(maxWidth: .infinity)
            .background(Color.init(red: 0.98, green: 0.98, blue: 0.98))
            .cornerRadius(14)
            .shadow(radius: 4)
            .padding(.top, 100)

            if activeField == 1 {
                SuggestionTextFieldMenu(editing: $editing, text: $inputText)
                    .padding(.top, 35)
            } else if activeField == 2 {
                SuggestionTextFieldMenu(editing: $editing, text: $inputText)
                    .padding(.top, 135)
            }
        }
        .padding(20)
    }
    .frame(maxHeight: 360)
}

Screenshot

© www.soinside.com 2019 - 2024. All rights reserved.