如何正确更新修饰符?

时间:2019-09-21 01:08:52

标签: swift swiftui

我试图在存在文本字段时将视图中的每个对象上移,并且为了减少代码量,我尝试将修饰符制作为修饰符类,但是问题是当y值更改为键盘处理程序,它不会移动。如果您不使用单独的函数,则此确切的代码将起作用,因此我不知道出了什么问题。

我尝试将y的值设置为修饰符中的一个状态,但是它仍然不会更新-就像我说的,如果不在定制修饰符中,它就可以工作。

ContentView.swift

struct ContentView: View {
    @State private var name = Array<String>.init(repeating: "", count: 3)
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)


    var body: some View {
        Background {
            VStack {
                Group {
                    Text("Some filler text").font(.largeTitle)
                    Text("Some filler text").font(.largeTitle)
                }

                TextField("enter text #1", text: self.$name[0])
                    .textFieldStyle(RoundedBorderTextFieldStyle())

                TextField("enter text #2", text: self.$name[1])
                    .textFieldStyle(RoundedBorderTextFieldStyle())

                TextField("enter text #3", text: self.$name[2])
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .background(GeometryGetter(rect: self.$kGuardian.rects[0]))

            }
        }.modifier(BetterTextField(kGuardian: kGuardian, slide: kGuardian.slide))
    }

}

KeyboardModifications.swift

struct GeometryGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { geometry in
            Group { () -> AnyView in
                DispatchQueue.main.async {
                    self.rect = geometry.frame(in: .global)
                }

                return AnyView(Color.clear)
            }
        }
    }
}

final class KeyboardGuardian: ObservableObject {
    public var rects: Array<CGRect>
    public var keyboardRect: CGRect = CGRect()

    // keyboardWillShow notification may be posted repeatedly,
    // this flag makes sure we only act once per keyboard appearance
    public var keyboardIsHidden = true

    @Published var slide: CGFloat = 0
    var appearenceDuration : Double = 0

    var showField: Int = 0 {
        didSet {
            updateSlide()
        }
    }

    init(textFieldCount: Int) {
        self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)

        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)

    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {

        guard let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else {return}
        appearenceDuration = duration

        if keyboardIsHidden {
            keyboardIsHidden = false
            if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
                keyboardRect = rect
                updateSlide()
            }
        }
    }

    @objc func keyBoardWillHide(notification: Notification) {
        keyboardIsHidden = true
        updateSlide()
    }

    func updateSlide() {
        if keyboardIsHidden {
            slide = 0
        } else {
            let tfRect = self.rects[self.showField]
            let diff = keyboardRect.minY - tfRect.maxY

            if diff > 0 {
                slide += diff
            } else {
                slide += min(diff, 0)
            }

        }
    }
}

struct Background<Content: View>: View {
    private var content: Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content()
    }

    var body: some View {
        Color.white
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        .overlay(content)
    }
}

自定义修饰符类:

struct BetterTextField: ViewModifier {
    public var kGuardian : KeyboardGuardian
    @State public var slide : CGFloat
    func body(content: Content) -> some View {
        content
        .offset(y: slide).animation(.easeIn(duration: kGuardian.appearenceDuration))
        .onTapGesture {
            let keyWindow = UIApplication.shared.connectedScenes
                               .filter({$0.activationState == .foregroundActive})
                               .map({$0 as? UIWindowScene})
                               .compactMap({$0})
                               .first?.windows
                               .filter({$0.isKeyWindow}).first
            keyWindow!.endEditing(true)
        }
    }
}

应该发生的是,整个屏幕都应该通过键盘向上移动,但是仍然保持不变。我已经尝试了大约2个小时,但仍无济于事。

1 个答案:

答案 0 :(得分:1)

我猜您的幻灯片变量未更新。在BetterTextField修饰符中尝试以下更改代码:

struct BetterTextField: ViewModifier {
    @ObservedObject var kGuardian : KeyboardGuardian
    func body(content: Content) -> some View {
        content
            .offset(y: kGuardian.slide).animation(.easeIn(duration: kGuardian.appearenceDuration))
        .onTapGesture {
            let keyWindow = UIApplication.shared.connectedScenes
                               .filter({$0.activationState == .foregroundActive})
                               .map({$0 as? UIWindowScene})
                               .compactMap({$0})
                               .first?.windows
                               .filter({$0.isKeyWindow}).first
            keyWindow!.endEditing(true)
        }
    }
}