首页 > 解决方案 > 如何正确更新修饰符?

问题描述

当存在文本字段时,我试图让视图中的每个对象都向上移动,并且为了减少代码量,我尝试将修饰符变成修饰符类,但问题是当 y 值更改为键盘处理程序,它不会移动。如果你不使用单独的函数,这个确切的代码就可以工作,所以我不知道出了什么问题。

我已经尝试在修饰符中设置 ya 状态的值,但它仍然没有更新 - 就像我说的,如果它不在自定义修饰符中,它就可以工作。

内容视图.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 个小时,但无济于事。

标签: swiftswiftui

解决方案


我猜你的幻灯片变量没有更新。尝试在 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)
        }
    }
}

推荐阅读