Hit*_*esh 31 ios swift swiftui
TextField我的主箱里有七个ContentView。当用户打开键盘时,其中一些TextField隐藏在键盘框架下。所以TextField当键盘出现时,我想分别向上移动。
我已使用以下代码TextField在屏幕上添加。
struct ContentView : View {
@State var textfieldText: String = ""
var body: some View {
VStack {
TextField($textfieldText, placeholder: Text("TextField1"))
TextField($textfieldText, placeholder: Text("TextField2"))
TextField($textfieldText, placeholder: Text("TextField3"))
TextField($textfieldText, placeholder: Text("TextField4"))
TextField($textfieldText, placeholder: Text("TextField5"))
TextField($textfieldText, placeholder: Text("TextField6"))
TextField($textfieldText, placeholder: Text("TextField6"))
TextField($textfieldText, placeholder: Text("TextField7"))
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Pre*_*zic 62
我尝试了许多建议的解决方案,尽管它们在大多数情况下都有效,但我遇到了一些问题 - 主要是安全区域(我在 TabView 的选项卡中有一个表单)。
我最终结合了几个不同的解决方案,并使用 GeometryReader 来获取特定视图的安全区域底部插图并在填充计算中使用它:
import SwiftUI
import Combine
struct AdaptsToKeyboard: ViewModifier {
@State var currentHeight: CGFloat = 0
func body(content: Content) -> some View {
GeometryReader { geometry in
content
.padding(.bottom, self.currentHeight)
.onAppear(perform: {
NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillShowNotification)
.merge(with: NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillChangeFrameNotification))
.compactMap { notification in
withAnimation(.easeOut(duration: 0.16)) {
notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
}
}
.map { rect in
rect.height - geometry.safeAreaInsets.bottom
}
.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillHideNotification)
.compactMap { notification in
CGFloat.zero
}
.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
})
}
}
}
extension View {
func adaptsToKeyboard() -> some View {
return modifier(AdaptsToKeyboard())
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
struct MyView: View {
var body: some View {
Form {...}
.adaptsToKeyboard()
}
}
Run Code Online (Sandbox Code Playgroud)
Moj*_*ini 43
从 iOS 14.2 开始,如果TextFields 有足够的移动空间,则默认情况下它们是键盘感知的。例如,如果它在一个VStack带一个Spacer(看下面没有修饰符的旧演示代码)
将此修饰符添加到 TextField
.ignoresSafeArea(.keyboard, edges: .bottom)
Run Code Online (Sandbox Code Playgroud)
Apple 添加了键盘作为安全区域的区域,因此您可以使用它像其他区域一样使用键盘移动任何View区域。
小智 29
我创建了一个非常简单易用的视图修改器。
使用下面的代码添加一个 Swift 文件,然后将此修饰符添加到您的视图中:
.keyboardResponsive()
Run Code Online (Sandbox Code Playgroud)
import SwiftUI
struct KeyboardResponsiveModifier: ViewModifier {
@State private var offset: CGFloat = 0
func body(content: Content) -> some View {
content
.padding(.bottom, offset)
.onAppear {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notif in
let value = notif.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
let height = value.height
let bottomInset = UIApplication.shared.windows.first?.safeAreaInsets.bottom
self.offset = height - (bottomInset ?? 0)
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { notif in
self.offset = 0
}
}
}
}
extension View {
func keyboardResponsive() -> ModifiedContent<Self, KeyboardResponsiveModifier> {
return modifier(KeyboardResponsiveModifier())
}
}
Run Code Online (Sandbox Code Playgroud)
kon*_*iki 27
为Xcode beta 7更新了代码。
您无需填充,ScrollViews或List即可实现此目的。尽管此解决方案也可以很好地与他们一起使用。我在这里包括两个例子。
第一个将所有 textField向上移动(如果其中任何一个出现了键盘)。但仅在需要时。如果键盘没有隐藏文本字段,它们将不会移动。
在第二个示例中,视图仅移动了足够的距离,以避免隐藏活动的文本字段。
两个示例都使用末尾相同的通用代码:GeometryGetter和KeyboardGuardian
struct ContentView: View {
@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)
@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {
Group {
Text("Some filler text").font(.largeTitle)
Text("Some filler text").font(.largeTitle)
}
TextField("enter text #1", text: $name[0])
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #2", text: $name[1])
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #3", text: $name[2])
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[0]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
}
}
Run Code Online (Sandbox Code Playgroud)
struct ContentView: View {
@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 3)
@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {
Group {
Text("Some filler text").font(.largeTitle)
Text("Some filler text").font(.largeTitle)
}
TextField("text #1", text: $name[0], onEditingChanged: { if $0 { self.kGuardian.showField = 0 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[0]))
TextField("text #2", text: $name[1], onEditingChanged: { if $0 { self.kGuardian.showField = 1 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[1]))
TextField("text #3", text: $name[2], onEditingChanged: { if $0 { self.kGuardian.showField = 2 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[2]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
}.onAppear { self.kGuardian.addObserver() }
.onDisappear { self.kGuardian.removeObserver() }
}
Run Code Online (Sandbox Code Playgroud)
该视图吸收了其父视图的大小和位置。为了实现这一点,它在.background修饰符内部被调用。这是一个非常强大的修饰符,不仅是装饰视图背景的一种方式。将视图传递给.background(MyView())时,MyView会将修改后的视图作为父视图。使用GeometryReader可以使视图知道父级的几何。
例如:Text("hello").background(GeometryGetter(rect: $bounds))将使用文本视图的大小和位置以及全局坐标空间填充变量边界。
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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新我添加了DispatchQueue.main.async,以避免在渲染视图时修改视图状态的可能性。
KeyboardGuardian的目的是跟踪键盘显示/隐藏事件并计算视图需要移动多少空间。
更新: 当用户从一个字段切换到另一个字段时,我修改了KeyboardGuardian以刷新幻灯片
import SwiftUI
import Combine
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 showField: Int = 0 {
didSet {
updateSlide()
}
}
init(textFieldCount: Int) {
self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)
}
func addObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}
func removeObserver() {
NotificationCenter.default.removeObserver(self)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if keyboardIsHidden {
keyboardIsHidden = false
if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
keyboardRect = rect
updateSlide()
}
}
}
@objc func keyBoardDidHide(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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ami*_*ant 19
或者你可以只使用IQKeyBoardManagerSwift
并且可以选择将此添加到您的应用程序委托以隐藏工具栏并在单击除键盘之外的任何视图时启用键盘隐藏。
IQKeyboardManager.shared.enableAutoToolbar = false
IQKeyboardManager.shared.shouldShowToolbarPlaceholder = false
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.previousNextDisplayMode = .alwaysHide
Run Code Online (Sandbox Code Playgroud)
Ben*_*dle 18
我创建了一个视图,该视图可以包装任何其他视图以在键盘出现时缩小视图。
很简单 我们为键盘显示/隐藏事件创建发布者,然后使用订阅它们onReceive。我们使用该结果在键盘后面创建一个键盘大小的矩形。
struct KeyboardHost<Content: View>: View {
let view: Content
@State private var keyboardHeight: CGFloat = 0
private let showPublisher = NotificationCenter.Publisher.init(
center: .default,
name: UIResponder.keyboardWillShowNotification
).map { (notification) -> CGFloat in
if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
return rect.size.height
} else {
return 0
}
}
private let hidePublisher = NotificationCenter.Publisher.init(
center: .default,
name: UIResponder.keyboardWillHideNotification
).map {_ -> CGFloat in 0}
// Like HStack or VStack, the only parameter is the view that this view should layout.
// (It takes one view rather than the multiple views that Stacks can take)
init(@ViewBuilder content: () -> Content) {
view = content()
}
var body: some View {
VStack {
view
Rectangle()
.frame(height: keyboardHeight)
.animation(.default)
.foregroundColor(.clear)
}.onReceive(showPublisher.merge(with: hidePublisher)) { (height) in
self.keyboardHeight = height
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用如下视图:
var body: some View {
KeyboardHost {
viewIncludingKeyboard()
}
}
Run Code Online (Sandbox Code Playgroud)
要向上移动视图的内容而不是缩小视图,可以添加填充或偏移量,view而不是将其放入带有矩形的VStack中。
Mic*_*eas 10
为了构建@rraphael的解决方案,我将其转换为可以通过今天的xcode11 swiftUI支持使用。
import SwiftUI
final class KeyboardResponder: ObservableObject {
private var notificationCenter: NotificationCenter
@Published private(set) var currentHeight: CGFloat = 0
init(center: NotificationCenter = .default) {
notificationCenter = center
notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
deinit {
notificationCenter.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
currentHeight = 0
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
struct ContentView: View {
@ObservedObject private var keyboard = KeyboardResponder()
@State private var textFieldInput: String = ""
var body: some View {
VStack {
HStack {
TextField("uMessage", text: $textFieldInput)
}
}.padding()
.padding(.bottom, keyboard.currentHeight)
.edgesIgnoringSafeArea(.bottom)
.animation(.easeOut(duration: 0.16))
}
}
Run Code Online (Sandbox Code Playgroud)
发布会currentHeight触发UI的重新渲染,并在键盘显示时将TextField上移,而在关闭时将其下移。但是我没有使用ScrollView。
我审查了现有的解决方案并将其重构为一个方便的 SPM 包,该包提供了一个.keyboardAware()修改器:

例子:
struct KeyboardAwareView: View {
@State var text = "example"
var body: some View {
NavigationView {
ScrollView {
VStack(alignment: .leading) {
ForEach(0 ..< 20) { i in
Text("Text \(i):")
TextField("Text", text: self.$text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.bottom, 10)
}
}
.padding()
}
.keyboardAware() // <--- the view modifier
.navigationBarTitle("Keyboard Example")
}
}
}
Run Code Online (Sandbox Code Playgroud)
来源:
import UIKit
import SwiftUI
public class KeyboardInfo: ObservableObject {
public static var shared = KeyboardInfo()
@Published public var height: CGFloat = 0
private init() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIApplication.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
@objc func keyboardChanged(notification: Notification) {
if notification.name == UIApplication.keyboardWillHideNotification {
self.height = 0
} else {
self.height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
}
}
}
struct KeyboardAware: ViewModifier {
@ObservedObject private var keyboard = KeyboardInfo.shared
func body(content: Content) -> some View {
content
.padding(.bottom, self.keyboard.height)
.edgesIgnoringSafeArea(self.keyboard.height > 0 ? .bottom : [])
.animation(.easeOut)
}
}
extension View {
public func keyboardAware() -> some View {
ModifiedContent(content: self, modifier: KeyboardAware())
}
}
Run Code Online (Sandbox Code Playgroud)
您需要添加a ScrollView并设置键盘大小的底部填充,以便当键盘出现时内容可以滚动。
要获取键盘尺寸,您将需要使用“ NotificationCenter注册键盘”事件。您可以使用自定义类来这样做:
import SwiftUI
import Combine
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) {
print("keyboard will show")
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
print("keyboard will hide")
currentHeight = 0
}
}
Run Code Online (Sandbox Code Playgroud)
该BindableObject一致性将允许您使用这个类的State,并触发视图更新。如果需要,请查看以下教程BindableObject:SwiftUI教程
When you get that, you need to configure a ScrollView to reduce its size when the keyboard appear. For convenience I wrapped this ScrollView into some kind of component:
struct KeyboardScrollView<Content: View>: View {
@State var keyboard = KeyboardResponder()
private var content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ScrollView {
VStack {
content
}
}
.padding(.bottom, keyboard.currentHeight)
}
}
Run Code Online (Sandbox Code Playgroud)
All you have to do now is to embed your content inside the custom ScrollView.
struct ContentView : View {
@State var textfieldText: String = ""
var body: some View {
KeyboardScrollView {
ForEach(0...10) { index in
TextField(self.$textfieldText, placeholder: Text("TextField\(index)")) {
// Hide keyboard when uses tap return button on keyboard.
self.endEditing(true)
}
}
}
}
private func endEditing(_ force: Bool) {
UIApplication.shared.keyWindow?.endEditing(true)
}
}
Run Code Online (Sandbox Code Playgroud)
Edit:
The scroll behaviour is really weird when the keyboard is hiding. Maybe using an animation to update the padding would fix this, or you should consider using something else than the padding to adjust the scroll view size.
用法:
import SwiftUI
var body: some View {
ScrollView {
VStack {
/*
TextField()
*/
}
}.keyboardSpace()
}
Run Code Online (Sandbox Code Playgroud)
代码:
import SwiftUI
import Combine
let keyboardSpaceD = KeyboardSpace()
extension View {
func keyboardSpace() -> some View {
modifier(KeyboardSpace.Space(data: keyboardSpaceD))
}
}
class KeyboardSpace: ObservableObject {
var sub: AnyCancellable?
@Published var currentHeight: CGFloat = 0
var heightIn: CGFloat = 0 {
didSet {
withAnimation {
if UIWindow.keyWindow != nil {
//fix notification when switching from another app with keyboard
self.currentHeight = heightIn
}
}
}
}
init() {
subscribeToKeyboardEvents()
}
private let keyboardWillOpen = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
.map { $0.height - (UIWindow.keyWindow?.safeAreaInsets.bottom ?? 0) }
private let keyboardWillHide = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }
private func subscribeToKeyboardEvents() {
sub?.cancel()
sub = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
.subscribe(on: RunLoop.main)
.assign(to: \.self.heightIn, on: self)
}
deinit {
sub?.cancel()
}
struct Space: ViewModifier {
@ObservedObject var data: KeyboardSpace
func body(content: Content) -> some View {
VStack(spacing: 0) {
content
Rectangle()
.foregroundColor(Color(.clear))
.frame(height: data.currentHeight)
.frame(maxWidth: .greatestFiniteMagnitude)
}
}
}
}
extension UIWindow {
static var keyWindow: UIWindow? {
let keyWindow = UIApplication.shared.connectedScenes
.first { $0.activationState == .foregroundActive }
.flatMap { $0 as? UIWindowScene }?.windows
.first { $0.isKeyWindow }
return keyWindow
}
}
Run Code Online (Sandbox Code Playgroud)
我使用 Benjamin Kindle 的回答作为起点,但我有几个问题想要解决。
keyboardWillChangeFrameNotification到处理的通知列表解决了这个问题。init接受 a的函数,@ViewBuilder以便您可以KeyboardHost像使用任何其他 View 一样使用该视图,并且只需在尾随闭包中传递您的内容,而不是将内容视图作为参数传递给init.Rectangle调整底部填充的 。UIWindowas 中提供的字符串,而不是使用硬编码的“UIKeyboardFrameEndUserInfoKey”字符串UIWindow.keyboardFrameEndUserInfoKey。把所有这些放在一起,我有:
struct KeyboardHost<Content>: View where Content: View {
var content: Content
/// The current height of the keyboard rect.
@State private var keyboardHeight = CGFloat(0)
/// A publisher that combines all of the relevant keyboard changing notifications and maps them into a `CGFloat` representing the new height of the
/// keyboard rect.
private let keyboardChangePublisher = NotificationCenter.Publisher(center: .default,
name: UIResponder.keyboardWillShowNotification)
.merge(with: NotificationCenter.Publisher(center: .default,
name: UIResponder.keyboardWillChangeFrameNotification))
.merge(with: NotificationCenter.Publisher(center: .default,
name: UIResponder.keyboardWillHideNotification)
// But we don't want to pass the keyboard rect from keyboardWillHide, so strip the userInfo out before
// passing the notification on.
.map { Notification(name: $0.name, object: $0.object, userInfo: nil) })
// Now map the merged notification stream into a height value.
.map { ($0.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero).size.height }
// If you want to debug the notifications, swap this in for the final map call above.
// .map { (note) -> CGFloat in
// let height = (note.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero).size.height
//
// print("Received \(note.name.rawValue) with height \(height)")
// return height
// }
var body: some View {
content
.onReceive(keyboardChangePublisher) { self.keyboardHeight = $0 }
.padding(.bottom, keyboardHeight)
.animation(.default)
}
init(@ViewBuilder _ content: @escaping () -> Content) {
self.content = content()
}
}
struct KeyboardHost_Previews: PreviewProvider {
static var previews: some View {
KeyboardHost {
TextField("TextField", text: .constant("Preview text field"))
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的一些解决方案存在一些问题,不一定是“最干净”的方法。因此,我为下面的实现修改了一些内容。
extension View {
func onKeyboard(_ keyboardYOffset: Binding<CGFloat>) -> some View {
return ModifiedContent(content: self, modifier: KeyboardModifier(keyboardYOffset))
}
}
struct KeyboardModifier: ViewModifier {
@Binding var keyboardYOffset: CGFloat
let keyboardWillAppearPublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
let keyboardWillHidePublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
init(_ offset: Binding<CGFloat>) {
_keyboardYOffset = offset
}
func body(content: Content) -> some View {
return content.offset(x: 0, y: -$keyboardYOffset.wrappedValue)
.animation(.easeInOut(duration: 0.33))
.onReceive(keyboardWillAppearPublisher) { notification in
let keyWindow = UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.map { $0 as? UIWindowScene }
.compactMap { $0 }
.first?.windows
.filter { $0.isKeyWindow }
.first
let yOffset = keyWindow?.safeAreaInsets.bottom ?? 0
let keyboardFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? .zero
self.$keyboardYOffset.wrappedValue = keyboardFrame.height - yOffset
}.onReceive(keyboardWillHidePublisher) { _ in
self.$keyboardYOffset.wrappedValue = 0
}
}
}
Run Code Online (Sandbox Code Playgroud)
struct RegisterView: View {
@State var name = ""
@State var keyboardYOffset: CGFloat = 0
var body: some View {
VStack {
WelcomeMessageView()
TextField("Type your name...", text: $name).bordered()
}.onKeyboard($keyboardYOffset)
.background(WelcomeBackgroundImage())
.padding()
}
}
Run Code Online (Sandbox Code Playgroud)
我本来希望采用更简洁的方法,并将如何偏移内容的责任转移到构建的视图(而不是修饰符)上,但是在将偏移代码移动到视图时,似乎我无法让发布者正确触发。 ...
另请注意,在此实例中必须使用 Publishers,因为final class当前会导致未知的异常崩溃(即使它满足接口要求),并且在应用偏移代码时,整体 ScrollView 是最佳方法。
说实话,很多这些答案似乎真的很臃肿。如果您使用的是 SwiftUI,那么您也可以使用 Combine。
KeyboardResponder如下图创建一个,然后就可以像前面演示的那样使用了。
针对 iOS 14 更新。
import Combine
import UIKit
final class KeyboardResponder: ObservableObject {
@Published var keyboardHeight: CGFloat = 0
init() {
NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
.compactMap { notification in
(notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height
}
.receive(on: DispatchQueue.main)
.assign(to: \.keyboardHeight)
}
}
struct ExampleView: View {
@ObservedObject private var keyboardResponder = KeyboardResponder()
@State private var text: String = ""
var body: some View {
VStack {
Text(text)
Spacer()
TextField("Example", text: $text)
}
.padding(.bottom, keyboardResponder.keyboardHeight)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5968 次 |
| 最近记录: |