You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:24:53