如何在UITextField中同时显示清除按钮与单位标签(仿苹果健康App)
复刻苹果健康App体重输入框交互的解决方案
UIKit 实现方案
系统默认的 UITextField 会让 rightView 覆盖自带的清除按钮,因此需要自定义容器视图整合单位标签和清除按钮,再手动控制清除按钮的显示逻辑。
代码示例
// 初始化TextField let textField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 44)) textField.placeholder = "输入体重" textField.borderStyle = .roundedRect // 创建容器视图,适配标签和按钮的宽度 let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 65, height: textField.frame.height)) // 添加单位标签 let unitLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 35, height: containerView.frame.height)) unitLabel.text = "kg" unitLabel.textAlignment = .center unitLabel.font = textField.font containerView.addSubview(unitLabel) // 添加自定义清除按钮 let clearButton = UIButton(type: .system) clearButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) clearButton.tintColor = .systemGray clearButton.frame = CGRect(x: unitLabel.frame.maxX + 5, y: (containerView.frame.height - 22)/2, width: 22, height: 22) clearButton.addTarget(self, action: #selector(clearText), for: .touchUpInside) clearButton.isHidden = true // 默认隐藏 containerView.addSubview(clearButton) // 配置TextField textField.rightView = containerView textField.rightViewMode = .always textField.addTarget(self, action: #selector(updateClearButtonVisibility), for: .editingDidBegin) textField.addTarget(self, action: #selector(updateClearButtonVisibility), for: .editingDidEnd) textField.addTarget(self, action: #selector(updateClearButtonVisibility), for: .editingChanged) // 清除文本方法 @objc func clearText() { textField.text = "" updateClearButtonVisibility() } // 更新清除按钮显示状态 @objc func updateClearButtonVisibility() { guard let clearButton = textField.rightView?.subviews.first(where: { $0 is UIButton }) as? UIButton else { return } clearButton.isHidden = !textField.isEditing || (textField.text?.isEmpty ?? true) }
逻辑说明
- 关闭系统自带的
clearButtonMode,改用自定义按钮避免和rightView冲突 - 监听编辑状态和文本内容变化,控制清除按钮的显示/隐藏,和系统
.whileEditing逻辑一致 - 容器视图确保单位标签始终显示,清除按钮仅在编辑且文本非空时出现
SwiftUI 实现方案
SwiftUI 可通过 overlay 直接在 TextField 上叠加组合视图,配合 @FocusState 追踪编辑状态,快速实现需求。
代码示例
struct WeightInputView: View { @State private var weightText = "" @FocusState private var isEditing: Bool var body: some View { TextField("输入体重", text: $weightText) .focused($isEditing) .padding(.horizontal, 16) .padding(.vertical, 12) .border(Color(.systemGray4), cornerRadius: 8) .overlay(alignment: .trailing) { HStack(spacing: 8) { Text("kg") .foregroundColor(.secondary) .font(.system(size: 16)) if isEditing && !weightText.isEmpty { Button(action: { weightText = "" }) { Image(systemName: "xmark.circle.fill") .foregroundColor(.secondary) .font(.system(size: 18)) } } } .padding(.trailing, 16) } .onTapGesture { isEditing = true } } }
逻辑说明
- 使用
@FocusState监测 TextField 是否处于编辑状态 - 通过
overlay在右侧叠加单位标签和条件显示的清除按钮 - 清除按钮仅在编辑且文本非空时显示,单位标签始终可见,完全匹配健康App的交互效果
内容的提问来源于stack exchange,提问作者Kngw Kngw
相关产品推荐
相关产品推荐

