Drew
Drew

Reputation: 47

How do I create a multiline Textfiled in SwiftUI?

I am trying to achieve this view (on screenshot). The user can type in something inside this box. He should be able to make new paragraphs, but text should no longer be than the box's height, for example with linelimit. Goal: Goal

However, when selecting TextField, the line keeps growing horizontally while typing. I tried to modify by adding ".linelimit(nil) but it doesn't work. Another approach by me was using textEditor: with TextEditor and without padding

But there is also the problem with missing placeholder and modifications to layout and text padding. When I add padding, the layout looks like this:

with TextEditor and with padding.

This is my situation with TextEditor:

struct Notes: View {


@State private var notes = ""

var body: some View {
        VStack (alignment: .leading, spacing: 5) {
            Text("Notes")
                .fontWeight(.bold)
        TextEditor(text: $notes)
            .submitLabel(.done)
            //.padding()
            .frame(height: 100, alignment: .top)
            //.background(Color(.systemGray5))
            .lineLimit(3)
            .cornerRadius(22)
            .multilineTextAlignment(.leading)
            .colorMultiply(Color(.systemGray5))
        }
        .frame(minWidth: 0, maxWidth: .infinity)
        .padding(.horizontal)
}
}

Is there an alternative I am missing?

Thanks for any advice and help. Kind regards.

Upvotes: 0

Views: 1617

Answers (1)

ChrisR
ChrisR

Reputation: 12125

Here is a 90% solution. It deletes further text after the 3rd line break, but it cannot detect line wraps in long texts.

struct ContentView: View {
    
    @State private var notes = ""
    
    var body: some View {
        
        VStack (alignment: .leading) {
            Text("Notes")
                .fontWeight(.bold)
            
            CustomTextEditor("Enter your note", text: $notes)
        }
        .padding()

    }
}


struct CustomTextEditor: View {
    
    init(_ prompt: LocalizedStringKey, text: Binding<String>) {
        self.prompt = prompt
        self._text = Binding(projectedValue: text)
    }
    let prompt: LocalizedStringKey
    @Binding var text: String
        
    var body: some View {
        ZStack(alignment: .topLeading ) {
            
            Text(prompt)
                .foregroundColor(text == "" ? .secondary : .clear)
                .padding(EdgeInsets(top: 7, leading: 3, bottom: 0, trailing: 0))
            
            TextEditor(text: $text)
            
            // deleting everything after the 3rd linebreak
                .onChange(of: text) { _ in
                    let stringArray = text.map { $0 }
                    let pos = stringArray.indices.filter { stringArray[$0] == "\n"}
                    if pos.count > 2 {
                        text = String(stringArray.prefix(upTo: pos[2]))
                    }
                }
        }
        .frame(height: 82)
        .padding(10)
        .background(Color(.systemGray5))
        .cornerRadius(20)
        
        // getting rid of TextEditor standard background
        .onAppear {
            UITextView.appearance().backgroundColor = .clear
        }
        .onDisappear {
            UITextView.appearance().backgroundColor = .systemGray5
        }
    }
}

Upvotes: 1

Related Questions