SwiftUI 4.0:如何让TextField紧贴键盘顶部无空隙?
SwiftUI 4.0图片编辑:消除TextField与键盘顶部空隙问题
问题描述
我正在使用SwiftUI 4.0开发类似Instagram、Snapchat的图片编辑功能:选择图片后,点击按钮即可在图片上添加文字。当前遇到的问题是TextField无法紧贴键盘顶部,两者之间存在空隙,希望消除该空隙,让TextField直接位于键盘正上方。已在Info.plist中添加隐私-照片库使用描述。
当前代码
import SwiftUI import PhotosUI struct KeyBoardOverlay: View { @FocusState private var isTextFieldFocused: Bool @State var text = "" var body: some View { TextField("", text: $text) .focused($isTextFieldFocused) .foregroundColor(.white) .background(Color.black.opacity(0.7)) .keyboardType(.alphabet) .disableAutocorrection(true) HStack { Button(action: { isTextFieldFocused = true }) { } } .padding([.vertical], 10) .padding([.horizontal], 15) .background(Color.black.opacity(0.4)) .clipShape(RoundedRectangle(cornerRadius: 25)) } } struct ShowImageView: View { @State private var selectedItem: [PhotosPickerItem] = [] @State private var mediaData: Data? var body: some View { VStack { PhotosPicker(selection: $selectedItem, maxSelectionCount: 1, matching: .any(of: [.images])) { Image(systemName: "photo") .resizable() .frame(width: 24, height: 24) .foregroundColor(Color(.black)) .ignoresSafeArea() }.onChange(of: selectedItem) { newMedia in DispatchQueue.main.async { guard let item = selectedItem.first else { return } item.loadTransferable(type: Data.self) { result in switch result { case .success(let data): if let data = data { self.mediaData = data } else { print("data is nil") } case .failure(let failure): fatalError("\(failure)") } } } } if let data = mediaData, let uiimage = UIImage(data: data) { Image(uiImage: uiimage) .resizable() .aspectRatio(contentMode: .fit) .padding(.top, 10) .overlay( VStack { KeyBoardOverlay() }.padding(.bottom), alignment: .bottom) } } } }
效果对比
- 当前效果:

- 期望效果:

解决方案
要消除TextField与键盘顶部的空隙,需要调整布局结构并监听键盘高度变化,动态调整输入栏位置:
1. 修复输入栏布局结构
原KeyBoardOverlay中TextField与按钮上下排列,导致布局冗余且间距不合理。将两者整合到同一个HStack中,优化视觉布局:
struct KeyBoardOverlay: View { @FocusState private var isTextFieldFocused: Bool @State var text = "" var body: some View { HStack(spacing: 10) { // 输入框 TextField("输入文字...", text: $text) .focused($isTextFieldFocused) .foregroundColor(.white) .padding(.vertical, 10) .padding(.horizontal, 15) .background(Color.black.opacity(0.7)) .clipShape(RoundedRectangle(cornerRadius: 20)) .keyboardType(.alphabet) .disableAutocorrection(true) // 激活输入框的按钮 Button(action: { isTextFieldFocused = true }) { Image(systemName: "text.bubble") .foregroundColor(.white) .frame(width: 40, height: 40) .background(Color.black.opacity(0.7)) .clipShape(Circle()) } } .padding(.horizontal, 15) .padding(.vertical, 8) .background(Color.black.opacity(0.4)) .clipShape(RoundedRectangle(cornerRadius: 25)) } }
2. 监听键盘高度动态调整位置
在ShowImageView中添加键盘监听,获取键盘高度后,通过偏移量让输入栏紧贴键盘顶部:
struct ShowImageView: View { @State private var selectedItem: [PhotosPickerItem] = [] @State private var mediaData: Data? // 存储键盘高度 @State private var keyboardHeight: CGFloat = 0 var body: some View { VStack { PhotosPicker(selection: $selectedItem, maxSelectionCount: 1, matching: .any(of: [.images])) { Image(systemName: "photo") .resizable() .frame(width: 24, height: 24) .foregroundColor(Color(.black)) .ignoresSafeArea() }.onChange(of: selectedItem) { newMedia in DispatchQueue.main.async { guard let item = selectedItem.first else { return } item.loadTransferable(type: Data.self) { result in switch result { case .success(let data): if let data = data { self.mediaData = data } else { print("data is nil") } case .failure(let failure): fatalError("\(failure)") } } } } if let data = mediaData, let uiimage = UIImage(data: data) { Image(uiImage: uiimage) .resizable() .aspectRatio(contentMode: .fit) .padding(.top, 10) .overlay( KeyBoardOverlay() // 根据键盘高度偏移输入栏 .offset(y: keyboardHeight > 0 ? -keyboardHeight : 0) // 忽略键盘区域的安全限制 .ignoresSafeArea(.keyboard), alignment: .bottom ) } } // 监听键盘弹出/收起通知 .onAppear { NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main ) { notification in let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero keyboardHeight = frame.height } NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main ) { _ in keyboardHeight = 0 } } .onDisappear { NotificationCenter.default.removeObserver(self) } } }
关键说明
- 布局优化:将TextField与按钮放在同一行,减少不必要的垂直间距,让输入栏更紧凑。
- 键盘监听:通过
NotificationCenter监听键盘的弹出和收起事件,获取键盘的准确高度。 - 动态偏移:利用
offset调整输入栏的垂直位置,当键盘弹出时,让输入栏的底部与键盘顶部完全贴合;键盘收起时恢复原位。 - 忽略安全区域:使用
ignoresSafeArea(.keyboard)让输入栏可以延伸到键盘上方的区域,避免系统默认的安全间距。
内容的提问来源于stack exchange,提问作者user1591668
相关产品推荐
相关产品推荐

