Skip to content

Instantly share code, notes, and snippets.

@Haeuncs
Forked from wata/CenteredTextView.swift
Last active August 17, 2020 06:42
Show Gist options
  • Save Haeuncs/197e8dc11fad49528ed638526cc7beca to your computer and use it in GitHub Desktop.
Save Haeuncs/197e8dc11fad49528ed638526cc7beca to your computer and use it in GitHub Desktop.
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