0

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.

1
  • So, essentially, you are looking for a TextEditor with a placeholder and the ability to have some margin around the field? Anything else? Commented Feb 22, 2022 at 14:21

1 Answer 1

1

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
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this works perfectly! I tested it under different conditions and it works every time. What do you mean by '90%'?
if you don't hit return but just keep on typing, it will not stop accepting input after 3 lines, and then the text will scroll up. I tried to fix this, but need more time, as its getting tricky then.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.