【问题标题】:Custom Text Input Change Label when blank空白时自定义文本输入更改标签
【发布时间】:2021-12-28 14:57:18
【问题描述】:

我正在为文本输入制作自定义标签。 这个想法是当文本输入改变时,标签也会随之改变。

我可以让它工作,只要我加载带有 id 值的视图,其中包含一些值,例如 1234 但如果我把它留空......

另外,它只存储那些值,当你输入文本输入时它不会改变。

效果有效,只是数字无效。

VStack {
                Custom_Input(id: "")
            }

它会引发以下错误。

Thread 1: Fatal error: String index is out of bounds

这很好用

VStack {
                Custom_Input(id: "1234")
            }

我不确定如何处理这个问题。

这是这里的整个视图。

import SwiftUI

struct Custom_Input: View {
    @State var id: String = " "
    @State var label1: Character = Character(" ")
    @State var label2: Character = Character(" ")
    @State var label3: Character = Character(" ")
    @State var label4: Character = Character(" ")

    
    var body: some View {

        ZStack {
            Color.green
            VStack {
                HStack(spacing: 13){
                    if(id.count < 1) {
                        Label("0", systemImage: "")
                            .frame(height: 48)
                            .padding(.leading, -7)
                            .foregroundColor(.black)
                    } else {
                        Label(String(label1), systemImage: "")
                        .foregroundColor(.white)
                        .frame(height: 48)
                        .padding(.leading, -7)
                        .foregroundColor(.white)
                    }
                    if(id.count < 2) {
                        Label("0", systemImage: "")
                            .frame(height: 48)
                            .padding(.leading, -7)
                            .foregroundColor(.black)
                    } else {
                    Label(String(label2), systemImage: "")
                        .foregroundColor(.white)
                        .frame(height: 48)
                        .padding(.leading, -7)
                        .foregroundColor(.white)
                    }
                    if(id.count < 3) {
                        Label("0", systemImage: "")
                            .frame(height: 48)
                            .padding(.leading, -7)
                            .foregroundColor(.black)
                    } else {
                    Label(String(label3), systemImage: "")
                        .foregroundColor(.white)
                        .frame(height: 48)
                        .padding(.leading, -7)
                        .foregroundColor(.white)
                    }
                    if(id.count < 4) {
                        Label("0", systemImage: "")
                            .frame(height: 48)
                            .padding(.leading, -7)
                            .foregroundColor(.black)
                    } else {
                    Label(String(label4), systemImage: "")
                        .foregroundColor(.white)
                        .frame(height: 48)
                        .padding(.leading, -7)
                        .foregroundColor(.white)
                    }
                }
                .onAppear {
                    label1 = id[0]
                    label2 = id[1]
                    label3 = id[2]
                    label4 = id[3]
                }
            .frame(width: 311, height: 48)
                
                TextField("", text: $id)
                    .background(.red)
                    .frame(width: 311, height: 48)
            }

        }
        
        .frame(width: 311, height: 48)
            
    }
}


extension StringProtocol {
    subscript(offset: Int) -> Character {
        self[index(startIndex, offsetBy: offset)]
    }
}


struct Custom_Input_Previews: PreviewProvider {
    static var previews: some View {
        Custom_Input(id: "1234")
    }
}

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    很多代码是重复的,可以简化。

    首先,为什么您的解决方案不起作用,为什么会导致运行时错误?好吧,当您使用 less 少于 4 个字符的字符串对其进行初始化时,您正在访问越界索引中的 StringonAppear(perform:) 在视图可见时立即运行,因此这是访问索引的位置导致错误。

    要解决此问题,您可以在需要/知道该角色存在时获取该角色。在下面的解决方案中,我创建了一个扩展来安全地获取索引,否则它返回nil

    extension StringProtocol {
        subscript(safe offset: Int) -> Character? {
            guard 0 ..< count ~= offset else {
                return nil
            }
            return self[index(startIndex, offsetBy: offset)]
        }
    }
    

    主视图代码已用ForEach 进行了简化,因此不必重复代码。布局也几乎相同,但大大简化。代码:

    struct CustomInput: View {
        @Binding var id: String
    
        var body: some View {
            VStack(spacing: 20) {
                HStack(spacing: 13) {
                    ForEach(0 ..< 4) { index in
                        Text(String(id[safe: index] ?? "0"))
                            .foregroundColor(id.count <= index ? .black : .white)
                    }
                }
    
                TextField("", text: $id)
                    .background(.red)
            }
            .padding(.vertical)
            .background(Color.green)
            .padding(30)
        }
    }
    

    用法:

    struct ContentView: View {
        @State private var id = ""
    
        var body: some View {
            CustomInput(id: $id)
        }
    }
    

    结果:

    【讨论】:

    • 太棒了!谢谢
    • 太棒了!谢谢你,我打算删除所有重复的代码,但我很感激你所做的。
    • @Bnd10706 太好了,很高兴它有用!
    猜你喜欢
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    相关资源
    最近更新 更多