I have a UITextView which I use as a text editor. However, I would like each new line to have a margin bottom.
Test text 1. Paragraph 1
Second paragraph. Test text 2
I have seen that it is not possible to do this from a paragraphStyle to since changing the line height
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5
but not setting the margin for each new line.
I tried to set paragraphSpacing but the various paragraphs have the right margin at the bottom but the height of the last line of the paragraph is different from the others and shows a spaced cursor.
paragraphStyle.paragraphSpacing = 20
I tried with a regex to translate each \n
to \n\n
func textViewDidChange(_ textView: UITextView) {
let newPattern = "(?<!\n)\n(?!\n)"
let regexOptions: NSRegularExpression.Options = [.anchorsMatchLines, .dotMatchesLineSeparators,]
but here too I got inaccurate results
Is it possible to set a margin bottom for each new line in a text editor?
Any ideas on how to proceed?
Based on this answer: https://stackoverflow.com/a/20311650/6257435 -- you can create a UITextView
subclass and override caretRect(for position: UITextPosition)
:
class MyTextView: UITextView {
override func caretRect(for position: UITextPosition) -> CGRect {
var superRect = super.caretRect(for: position)
guard let font = self.font else { return superRect }
// "descender" is expressed as a negative value,
// so to add its height you must subtract its value
superRect.size.height = font.pointSize - font.descender
return superRect
}
}
and here's an example - top is UITextView
(yellow background) bottom is MyTextView
(green background):
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let defaultTextView = UITextView()
defaultTextView.backgroundColor = .yellow
defaultTextView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(defaultTextView)
let myTextView = MyTextView()
myTextView.backgroundColor = .green
myTextView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myTextView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
defaultTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
defaultTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
defaultTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
defaultTextView.heightAnchor.constraint(equalToConstant: 200.0),
myTextView.topAnchor.constraint(equalTo: defaultTextView.bottomAnchor, constant: 20.0),
myTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
myTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
myTextView.heightAnchor.constraint(equalToConstant: 200.0),
])
let font = UIFont.systemFont(ofSize: 20)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacing = 32
let attributes: [NSAttributedString.Key: Any] = [
.font: font,
.foregroundColor: UIColor.blue,
.paragraphStyle: paragraphStyle
]
var testString = "UITextView Paragraph 1.\nParagraph 2 will be long enough to word wrap without line feeds.\nParagraph 3"
var attributedQuote = NSAttributedString(string: testString, attributes: attributes)
defaultTextView.attributedText = attributedQuote
testString = "MyTextView Paragraph 1.\nParagraph 2 will be long enough to word wrap without line feeds.\nParagraph 3"
attributedQuote = NSAttributedString(string: testString, attributes: attributes)
myTextView.attributedText = attributedQuote
}
}
Output: