swift - 如何正确更新修饰符?
问题描述
当存在文本字段时,我试图让视图中的每个对象都向上移动,并且为了减少代码量,我尝试将修饰符变成修饰符类,但问题是当 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 个小时,但无济于事。
解决方案
我猜你的幻灯片变量没有更新。尝试在 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)
}
}
}
推荐阅读
- three.js - Three.js GIS地图(连接图层/属性信息)
- graphql - 使用 AWS Amplify 和 Cognito 身份验证流程将用户详细信息保存到 graphql 数据库
- tensorflow - Tensorflow 2 模型以单个输出运行,但以多个输出失败。无法挤压 dim[2],预期维度为 1,得到 3
- c# - C# 对象、列表、数据网格。需要帮助来显示它
- amazon-web-services - 测试失败时 AWS CodeBuild 不会失败
- azure - Set-AzContext:请提供有效的租户或有效的订阅
- python - 如何优化参数的权重?
- sql - SQL-查找缺失值和分组
- azure-functions - Azure 函数依赖项
- pytorch - 在 pytorch-geometric 中加载单个图像