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

SwiftUI TextField实现不可选中后缀及值为0时隐藏的方案

实现带不可选中后缀的数值TextField(值为0时显示占位符)

需要实现一个TextField,满足以下需求:

  • 显示不可选中、不可编辑的后缀(如单位)
  • 当值为0时,隐藏数值并显示占位符
  • 解决原方案中NumberFormatter在decimalPad下无法实时更新、后缀可被删除的问题

核心思路是通过组合TextField和独立Text视图实现不可编辑的后缀,同时手动处理输入过滤、数值转换和显示逻辑,替代NumberFormatter的实时格式化限制:

完整实现代码

struct SuffixTextFieldView: View {
    @State private var inputText = ""
    @State private var value = 0.0
    private let suffix = "SUFFIX"
    private let placeholder = "Cost"
    
    var body: some View {
        HStack(spacing: 0) {
            TextField("", text: $inputText)
                .placeholder(when: inputText.isEmpty && value == 0.0) {
                    Text(placeholder)
                        .foregroundColor(.secondary)
                }
                .keyboardType(.decimalPad)
                .onChange(of: inputText) { newValue in
                    // 过滤输入,只保留数字和单个小数点
                    let filtered = newValue.filter { "0123456789.".contains($0) }
                    if filtered != newValue {
                        inputText = filtered
                    }
                    // 转换为数值,处理空输入的情况
                    if let number = Double(filtered) {
                        value = number
                    } else if filtered.isEmpty {
                        value = 0.0
                    }
                }
                .onEditingChanged { isEditing in
                    if !isEditing {
                        // 失去焦点时格式化显示:值为0则清空输入框(显示占位符)
                        if value == 0.0 {
                            inputText = ""
                        } else {
                            inputText = String(format: "%.2f", value)
                        }
                    } else {
                        // 开始编辑时,若当前值为0则清空输入框
                        if value == 0.0 {
                            inputText = ""
                        }
                    }
                }
            
            // 仅当值不为0时显示后缀,后缀为不可编辑的独立视图
            if value != 0.0 {
                Text(suffix)
                    .foregroundColor(.secondary)
                    .padding(.trailing, 8)
            }
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
        .background(Color(.systemGray6))
        .cornerRadius(8)
        .onAppear {
            // 初始值处理:非0值则格式化显示
            if value != 0.0 {
                inputText = String(format: "%.2f", value)
            }
        }
    }
}

// 自定义占位符扩展,实现值为0时显示占位符
extension View {
    func placeholder<Content: View>(
        when shouldShow: Bool,
        alignment: Alignment = .leading,
        @ViewBuilder placeholder: () -> Content
    ) -> some View {
        ZStack(alignment: alignment) {
            placeholder().opacity(shouldShow ? 1 : 0)
            self
        }
    }
}

#Preview {
    SuffixTextFieldView()
}

关键逻辑说明

  • 不可编辑后缀:通过HStack将TextField和独立的Text视图组合,后缀不属于TextField内容,因此无法被选中或删除,仅在值不为0时显示。
  • 输入过滤:在onChange中过滤输入内容,只允许数字和单个小数点,确保输入合法性。
  • 占位符控制:通过自定义placeholder扩展,在输入框为空且值为0时显示占位符。
  • 编辑状态处理:
    • 开始编辑时,若当前值为0则清空输入框,方便用户输入新数值。
    • 失去焦点时,自动格式化数值(保留两位小数),值为0则清空输入框显示占位符。
  • 实时数值同步:输入过程中实时将输入文本转换为数值,确保value状态与输入内容一致。

内容的提问来源于stack exchange,提问作者Elektronenhirn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:45:54