-
-
Save Haeuncs/197e8dc11fad49528ed638526cc7beca to your computer and use it in GitHub Desktop.
Avoid UITextView alignment bug. https://stackoverflow.com/questions/26524431/uitextview-alignment-caret-goes-left
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
class CenteredTextView: UITextView { | |
override init(frame: CGRect, textContainer: NSTextContainer?) { | |
super.init(frame: frame, textContainer: textContainer) | |
setup() | |
} | |
required init?(coder: NSCoder) { | |
super.init(coder: coder) | |
setup() | |
} | |
override func prepareForInterfaceBuilder() { | |
super.prepareForInterfaceBuilder() | |
setup() | |
} | |
private func setup() { | |
textAlignment = .center | |
// Avoid the bug of the text align changed to the left. | |
NotificationCenter.default.addObserver(forName: UITextView.textDidChangeNotification, object: self, queue: .main) { [weak self] (_) in | |
guard self?.textAlignment != .center else { return } | |
self?.textAlignment = .center | |
} | |
} | |
// Avoid the bug of the caret position changed to the left. | |
override func caretRect(for position: UITextPosition) -> CGRect { | |
let caretRect = super.caretRect(for: position) | |
let rangeOfCaret = NSRange(location: selectedRange.location + selectedRange.length, length: 0) | |
let rangeOfCharBeforeCaret = NSRange(location: rangeOfCaret.location > 0 ? rangeOfCaret.location - 1 : 0, length: 1) | |
let rangeOfCharAfterCaret = NSRange(location: rangeOfCaret.location, length: 1) | |
let fullRange = NSRange(location: 0, length: text.count) | |
// \n Added in the middle of String | |
let isMiddleOfString = NSLocationInRange(rangeOfCharBeforeCaret.location, fullRange) && | |
NSLocationInRange(NSMaxRange(rangeOfCharAfterCaret), fullRange) && | |
text.substring(with: rangeOfCharBeforeCaret) == "\n" && | |
text.substring(with: rangeOfCharAfterCaret) == "\n" | |
// \n Added in the end of String | |
let isEndOfString = NSMaxRange(rangeOfCharAfterCaret) >= NSMaxRange(fullRange) && | |
text.substring(with: rangeOfCharBeforeCaret) == "\n" | |
if isMiddleOfString || isEndOfString { | |
// Newline before and after the caret. Make it centered. | |
let correction = bounds.midX - caretRect.midX | |
let centeredCaretRect = caretRect.offsetBy(dx: correction, dy: 0) | |
return centeredCaretRect | |
} | |
else { | |
return caretRect | |
} | |
} | |
} | |
fileprivate extension String { | |
func substring(with nsrange: NSRange) -> Substring? { | |
guard let range = Range(nsrange, in: self) else { return nil } | |
return self[range] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment