简体   繁体   English

当键盘出现/消失时,带有 TextField 的 SwiftUI 列表会调整

[英]SwiftUI List with TextField adjust when keyboard appears/disappears

I have written a List with SwiftUI.我用 SwiftUI 写了一个列表。 I also have a TextField object which is used as a search bar.我还有一个用作搜索栏的 TextField 对象。 My code looks like this:我的代码如下所示:

import SwiftUI

struct MyListView: View {
    @ObservedObject var viewModel: MyViewModel

    @State private var query = ""

    var body: some View {

        NavigationView {
            List {
                // how to listen for changes here?
                // if I add onEditingChange here, Get the value only after the user finish search (by pressing enter on the keyboard)
                TextField(String.localizedString(forKey: "search_bar_hint"), text: self.$query) {
                    self.fetchListing()
                } 

                ForEach(viewModel.myArray, id: \.id) { arrayObject in
                    NavigationLink(destination: MyDetailView(MyDetailViewModel(arrayObj: arrayObject))) {
                         MyRow(arrayObj: arrayObject)
                    }
                }
            }
            .navigationBarTitle(navigationBarTitle())
        }
        .onAppear(perform: fetchListing)
    }

    private func fetchListing() {
        query.isEmpty ? viewModel.fetchRequest(for: nil) : viewModel.fetchRequest(for: query)
    }

    private func navigationBarTitle() -> String {
        return query.isEmpty ? String.localizedString(forKey: "my_title") : query
    }
}

The problem I have now is that the List remains behind the keyboard :(. How can I set the list padding bottom or edge insets (or whatever else works, I am totally open) so that the scrolling of the list ends above the keyboard? The list „size“ should also adjust automatically depending on if keyboard will be opened or closed.我现在遇到的问题是列表仍然在键盘后面:(。如何设置列表填充底部或边缘插入(或其他任何工作,我完全打开)以便列表的滚动在键盘上方结束?列表“大小”也应该根据键盘是打开还是关闭自动调整。

Problem looks like this:问题看起来像这样:

在此处输入图片说明

Please help me with any advice on this, I really have no idea how to do this :(. I am a SwiftUI beginner who is trying to learn it :).请帮助我对此提出任何建议,我真的不知道该怎么做:(。我是一名 SwiftUI 初学者,正在尝试学习它:)。

You may try the following and add detailed animations by yourself.您可以尝试以下操作并自行添加详细动画。

@ObservedObject var keyboard = KeyboardResponder()
var body: some View {

    NavigationView {

        List {
            // how to listen for changes here?
            // if I add onEditingChange here, Get the value only after the user finish search (by pressing enter on the keyboard)
            TextField("search_bar_hint", text: self.$query) {
                self.fetchListing()
            }

            ForEach(self.viewModel, id: \.self) { arrayObject in
                Text(arrayObject)
            }

        }.padding(.bottom, self.keyboard.currentHeight).animation(.easeIn(duration: self.keyboard.keyboardDuration))
            .navigationBarTitle(self.navigationBarTitle())
    }
    .onAppear(perform: fetchListing)
}





class KeyboardResponder: ObservableObject {
@Published var currentHeight: CGFloat = 0
@Published var keyboardDuration: TimeInterval = 0
private var anyCancellable: Set<AnyCancellable> = Set<AnyCancellable>()

init() {
    let publisher1 = NotificationCenter.Publisher(center: .default, name: UIResponder.keyboardWillShowNotification).map{ notification -> Just<(CGFloat, TimeInterval)> in
    guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {return Just((CGFloat(0.0), 0.0)) }
    guard let duration:TimeInterval = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return Just((CGFloat(0.0), 0.0)) }
    return Just((keyboardSize.height, duration))}

    let publisher2 = NotificationCenter.Publisher(center: .default, name: UIResponder.keyboardWillHideNotification) .map{ notification -> Just<(CGFloat, TimeInterval)> in
           guard let duration:TimeInterval = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return Just((CGFloat(0.0), 0.0)) }
               return Just((0.0, duration))}

    Publishers.Merge(publisher1, publisher2).switchToLatest().subscribe(on: RunLoop.main).sink(receiveValue: {
            if $0.1 > 1e-6 { self.currentHeight = $0.0 }
            self.keyboardDuration = $0.1
        }).store(in: &anyCancellable)
}
}

The resolution for the problem with the keyboard padding is like E.coms suggested.键盘填充问题的解决方案就像 E.coms 建议的那样。 Also the class written here by kontiki can be used:也可以使用 kontiki 在这里编写的类:

How to make the bottom button follow the keyboard display in SwiftUI 如何使底部按钮跟随 SwiftUI 中的键盘显示

The problems I had was because of state changes in my view hierarchy due to multiple instances of reference types publishing similar state changes.我遇到的问题是由于引用类型的多个实例发布了类似的状态更改导致我的视​​图层次结构中的状态更改。

My view models are reference types, which publish changes to its models, which are value types.我的视图模型是引用类型,它发布对其模型的更改,这是值类型。 However, these view models also contain reference types which handle network requests.然而,这些视图模型也包含处理网络请求的引用类型。 For each view I render (each row), I assign a new view model instance, which also creates a new network service instance.对于我渲染的每个视图(每一行),我分配一个新的视图模型实例,它还会创建一个新的网络服务实例。 Continuing this pattern, each of these network services also create and assign new network managers.继续这种模式,这些网络服务中的每一个也会创建和分配新的网络管理器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM