I have a customized text field that allows me to write multiple lines of text. However, I am wondering if there is a way to limit how many lines this text field will allow you to write. Setting a frame doesn't seem to work, as once you pass the frame's limit, you just continue to scroll down new lines. Something like TikTok or Instagram's edit bio forms, which after a certain amount of returns, you can't go any further.
Here is what I have so far:
struct NewSnippetTextEditor : UIViewRepresentable {
@Binding var txt : String
var doppleGray = Color(hue: 1.0, saturation: 0.058, brightness: 0.396)
@StateObject var profileData = ProfileViewModel()
func makeCoordinator() -> NewSnippetTextEditor.NewSnippetCoordinator {
return NewSnippetTextEditor.NewSnippetCoordinator(parent1: self)
}
func makeUIView(context: UIViewRepresentableContext<NewSnippetTextEditor>) -> UITextView {
let tview = UITextView()
tview.isEditable = true
tview.isUserInteractionEnabled = true
tview.isScrollEnabled = true
tview.text = "What's up..."
tview.textColor = .gray
tview.font = .systemFont(ofSize: 18)
tview.keyboardType = .twitter
tview.delegate = context.coordinator
return tview
}
func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<NewSnippetTextEditor>) {
}
class NewSnippetCoordinator : NSObject, UITextViewDelegate{
var parent : NewSnippetTextEditor
init(parent1 : NewSnippetTextEditor) {
parent = parent1
}
func textViewDidChange(_ textView: UITextView) {
self.parent.txt = textView.text
}
func textViewDidBeginEditing(_ textView: UITextView) {
textView.text = ""
textView.textColor = .label
}
}
}
And then to display this in a view I use:
NewSnippetTextEditor(txt: $newSnippetData.snippetTxt)
.cornerRadius(20)
.padding(EdgeInsets.init(top: 0, leading: 20, bottom: 0, trailing: 40))
.opacity(newSnippetData.isPosting ? 0.5 : 1)
.disabled(newSnippetData.isPosting ? true : false)
If this doesn't work for you, I also have another version that you might be able to better tweak.
struct NewSnippetTextView: UIViewRepresentable{
@Binding var text:String
@Binding var height:CGFloat
var placeholderText: String
@State var editing:Bool = false
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = true
textView.isScrollEnabled = true
textView.text = placeholderText
textView.delegate = context.coordinator
textView.textColor = UIColor.white
textView.backgroundColor = UIColor.black
textView.font = UIFont.systemFont(ofSize: 18)
textView.keyboardType = .twitter
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
if self.text.isEmpty == true{
textView.text = self.editing ? "" : self.placeholderText
textView.textColor = self.editing ? .white : .lightGray
}
DispatchQueue.main.async {
self.height = textView.contentSize.height
textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
}
func makeCoordinator() -> Coordinator {
NewSnippetTextView.Coordinator(self)
}
class Coordinator: NSObject, UITextViewDelegate{
var parent: NewSnippetTextView
init(_ params: NewSnippetTextView) {
self.parent = params
}
func textViewDidBeginEditing(_ textView: UITextView) {
DispatchQueue.main.async {
self.parent.editing = true
}
}
func textViewDidEndEditing(_ textView: UITextView) {
DispatchQueue.main.async {
self.parent.editing = false
}
}
func textViewDidChange(_ textView: UITextView) {
DispatchQueue.main.async {
self.parent.height = textView.contentSize.height
self.parent.text = textView.text
}
}
}
}
To display this second version I used:
NewSnippetTextView(text: $newSnippetData.snippetTxt, height: $textViewHeight, placeholderText: "What's up")
.frame(height: textViewHeight < 160 ? self.textViewHeight : 160)
.cornerRadius(20)
.padding(EdgeInsets.init(top: 0, leading: 20, bottom: 0, trailing: 40))
.opacity(newSnippetData.isPosting ? 0.5 : 1)
.disabled(newSnippetData.isPosting ? true : false)
CodePudding user response:
How about using a standard TextEditor and checking its length at change: (I admit it only counts characters, not lines, but you could implement that too by counting line breaks)
TextEditor(text: $textInput)
.onChange(of: textInput) { newValue in
if newValue.count > 30 {
textInput = String(newValue.dropLast(1))
}
}
