Ios 如何在SwiftUI中显示键盘时显示完整列表
当键盘显示时,如何显示完整的列表?键盘正在隐藏列表的下半部分 我的列表行中有一个文本字段。当键盘显示时,无法向下滚动查看完整列表。键盘位于列表的前面,而不是列表的“下方”。这是我的代码:Ios 如何在SwiftUI中显示键盘时显示完整列表,ios,swift,swiftui,Ios,Swift,Swiftui,当键盘显示时,如何显示完整的列表?键盘正在隐藏列表的下半部分 我的列表行中有一个文本字段。当键盘显示时,无法向下滚动查看完整列表。键盘位于列表的前面,而不是列表的“下方”。这是我的代码: struct ContentView: View { @State private var name = "" var body: some View { List { VStack { Text("Begin")
struct ContentView: View {
@State private var name = ""
var body: some View {
List {
VStack {
Text("Begin")
.frame(width: UIScreen.main.bounds.width)
.padding(.bottom, 400)
.background(Color.red)
TextField($name, placeholder: Text("enter text"), onEditingChanged: { _ in
//
}) {
//
}
Text("End")
.frame(width: UIScreen.main.bounds.width)
.padding(.top, 400)
.background(Color.green)
}
.listRowInsets(EdgeInsets())
}
}
}
有人能帮我怎么做吗
非常感谢。有一个用于处理键盘操作的,
您可以订阅如下键盘事件:
final class KeyboardResponder: BindableObject {
let didChange = PassthroughSubject<CGFloat, Never>()
private var _center: NotificationCenter
private(set) var currentHeight: CGFloat = 0 {
didSet {
didChange.send(currentHeight)
}
}
init(center: NotificationCenter = .default) {
_center = center
_center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
_center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
deinit {
_center.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
currentHeight = 0
}
}
@State var keyboard = KeyboardResponder()
var body: some View {
List {
VStack {
...
...
...
}.padding(.bottom, keyboard.currentHeight)
}
使用
Compose
的KeyboardResponder
对象的替代实现,如图所示
最终类键盘响应器:ObservableObject{
let willChange=PassthroughSubject()
专用(设置)变量currentHeight:长度=0{
意志{
willChange.send(当前高度)
}
}
let keyboard willopen=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillShowNotification)
.first()//keyboardWillShow通知可能会重复发布
.map{$0.userInfo![UIResponder.keyboardFrameEndUserInfoKey]as!CGRect}
.map{$0.height}
let keyboard willhide=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillHideNotification)
.map{CGFloat(0)中的{uuu}
func listen(){
_=发布者。合并(keyboardWillOpen,keyboardWillHide)
.subscribe(在:RunLoop.main上)
.assign(到:\.currentHeight,开:self)
}
init(){
听
}
}
更好的方法是将上述内容打包为
视图修改器
(大致改编自):
struct AdaptsToSoftwareKeyboard:ViewModifier{
@状态变量currentHeight:长度=0
func正文(内容:内容)->某些视图{
内容
.padding(.bottom,currentHeight)
.edgesIgnoringSafeArea(currentHeight==0?Edge.Set():.bottom)
.onAppear(执行:subscribeToKeyboardEvents)
}
private let keyboard willopen=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillShowNotification)
.map{$0.userInfo![UIResponder.keyboardFrameEndUserInfoKey]as!CGRect}
.map{$0.height}
private let keyboard willhide=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillHideNotification)
.map{长度为.zero}
私有函数subscribeToKeyboardEvents(){
_=发布者。合并(keyboardWillOpen,keyboardWillHide)
.subscribe(在:RunLoop.main上)
.assign(到:\.currentHeight,开:self)
}
}
然后可以这样使用:
final class KeyboardResponder: BindableObject {
let didChange = PassthroughSubject<CGFloat, Never>()
private var _center: NotificationCenter
private(set) var currentHeight: CGFloat = 0 {
didSet {
didChange.send(currentHeight)
}
}
init(center: NotificationCenter = .default) {
_center = center
_center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
_center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
deinit {
_center.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
currentHeight = 0
}
}
@State var keyboard = KeyboardResponder()
var body: some View {
List {
VStack {
...
...
...
}.padding(.bottom, keyboard.currentHeight)
}
组{
........
}.modifier(AdaptsToSoftwareKeyboard())
将Bogdan Farca的优秀联合收割机方法更新为XCode 11.2:
import Combine
import SwiftUI
struct AdaptsToSoftwareKeyboard: ViewModifier {
@State var currentHeight: CGFloat = 0
func body(content: Content) -> some View {
content
.padding(.bottom, self.currentHeight)
.edgesIgnoringSafeArea(self.currentHeight == 0 ? Edge.Set() : .bottom)
.onAppear(perform: subscribeToKeyboardEvents)
}
private let keyboardWillOpen = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
.map { $0.height }
private let keyboardWillHide = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }
private func subscribeToKeyboardEvents() {
_ = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
.subscribe(on: RunLoop.main)
.assign(to: \.self.currentHeight, on: self)
}
}
让观察者设置一个
环境值
。然后将其作为视图中的变量:
@Environment(\.keyboardHeight) var keyboardHeight: CGFloat
下面是
BindableObject
实现的更新版本(现在命名为observeObject
)
导入快捷界面
进口联合收割机
类KeyboardObserver:ObserveObject{
私有var可取消:任何可取消?
@已发布的专用(设置)var键盘高度:CGFloat=0
let keyboard willshow=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillShowNotification)
.compactMap{($0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey]as?cRect)?.height}
let keyboard willhide=NotificationCenter.default
.publisher(用于:UIResponder.keyboardWillHideNotification)
.map{{u0->CGFloat in 0}
init(){
Cancelable=发布者。合并(keyboardWillShow,keyboardWillHide)
.subscribe(在:RunLoop.main上)
.分配(至:\.键盘高度,打开:self)
}
}
以下是如何在视图中使用它:
@ObservedObject private var keyboardObserver=keyboardObserver()
var body:一些观点{
...
YourViewYouWantToRaise(你的观点)
.padding(.bottom,keyboardObserver.keyboardHeight)
.animation(.easeInOut(持续时间:0.3))
...
}
这些示例有点旧,我修改了一些代码以使用最近添加到SwiftUI的新功能,本文中可以找到此示例中使用的代码的详细说明:
键盘观察者课程:
用法:
一行解决方案
如果安装,只需在包含列表的视图上调用.padding(.keyboard)
。这是迄今为止我见过的最好、最简单的解决方案
import SwiftUIX
struct ExampleView: View {
var body: some View {
VStack {
List {
ForEach(contacts, id: \.self) { contact in
cellWithContact(contact)
}
}
}.padding(.keyboard) // This is all that's needed, super cool!
}
}
尝试订阅键盘显示/消失事件,并将底部边距应用于
VStack
我目前正在处理非常类似的事情(使用ScrollView而不是List)。我认为订阅键盘显示/隐藏事件是正确的方法。但这不是困难的部分。挑战在于找出活动文本字段的位置,以确定是否需要偏移量,如果需要,需要多少。你的具体例子会很简单,因为你有一个固定的400像素。。。不过,我假设这只是一个例子。我们的目标是能够确定文本字段相对于其父字段的相对位置,以及它滚动了多少,然后我们知道需要移动多少内容。您尝试过您的答案吗?尽管keyboard.currentHeight会更改,但视图不会移动。使用.offset(y:-keyboard.currentHeight)
它可以。但是,您的方法完全忽略了文本字段的实际位置。例如,如果列表被滚动,并且字段太高,当键盘出现时,文本字段就会从屏幕上移走。我喜欢你的答案,就是让键盘观察者在一个单独的类上,而不是在视图结构本身上。我可能会在以后更改我发布的答案,以遵循这种方法。我已经尝试了填充,并且效果很好(用户必须手动滚动,但内容将完全显示)。现在我再次阅读OP原始问题,我意识到他想要显示
import SwiftUIX
struct ExampleView: View {
var body: some View {
VStack {
List {
ForEach(contacts, id: \.self) { contact in
cellWithContact(contact)
}
}
}.padding(.keyboard) // This is all that's needed, super cool!
}
}