iOS - UITextview的简单使用
程序员文章站
2022-05-31 20:26:24
...
UITextView继承于UIScrollView,所以它也是一个可滚动控件。UITextView是我们开发过程中显示多行文本的首选,它支持显示大量文本内容,并且支持使用自定义样式信息和编辑功能。
首先我们创建一个UITextView,并设置部分属性
class ViewController: UIViewController {
lazy var textView: UITextView = {
let tv = UITextView()
// 背景颜色
tv.backgroundColor = UIColor.gray
// 文本内容
tv.text = "患难可以试验一个人的品格;非常的境遇才可以显出非常的气节;,风平浪静的海面,所有的船只都可以并驱竞争;命运的铁拳击中要害的时候,只有大勇大智的人才能够处之泰然。——莎士比亚"
// 文本颜色
tv.textColor = UIColor.white
// 文本字体大小
tv.font = UIFont.systemFont(ofSize: 18.0)
// 文本对齐方式
tv.textAlignment = .center
return tv
}()
override func viewDidLoad() {
super.viewDidLoad()
addTextView()
}
func addTextView() {
view.addSubview(textView)
textView.snp.makeConstraints { (make) in
make.left.top.right.bottom.equalToSuperview().inset(50)
}
}
}
效果如下:
常用属性
是否可以选中操作
textView.isSelectable = true
默认是true,可以选中,一旦设置为false,将不能够进行选中操作,默认可选中效果
富文本,可以通过设置attributedText属性设置文本样式,如:
// 创建可变属性字符串
let attribute = NSMutableAttributedString(string: textView.text)
// 设置段落样式
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineSpacing = 10
// 设置属性字典
let dic = [NSAttributedStringKey.foregroundColor: UIColor.red,
NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 22.0),
NSAttributedStringKey.paragraphStyle: paragraphStyle]
// 添加属性字典
attribute.addAttributes(dic, range: NSMakeRange(16, textView.text.count - 16))
// 设置textView的attributedText
textView.attributedText = attribute
输入视图
func addInputVeiw() {
let inputView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 200))
inputView.backgroundColor = UIColor.red
textView.inputView = inputView
}
输入键盘附属视图
func addInputAccessoryView(){
let inputAccessoryView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 100))
inputAccessoryView.backgroundColor = UIColor.red
textView.inputAccessoryView = inputAccessoryView
}
获得焦点后选中现有文本内容,输入内容时清除当前选中文本内容
textView.clearsOnInsertion = true
文本内容与边界的间距
textView.textContainerInset = UIEdgeInsetsMake(20, 20, 20, 20)
设置光标颜色
textView.tintColor = UIColor.red
代理函数
对于textView的输入进行监听,我们经常设置delegate,相关方法如下:
extension ViewController: UITextViewDelegate {
//将要开始编辑
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
return true
}
//将要开始编辑
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
return true
}
//已经开始编辑
func textViewDidBeginEditing(_ textView: UITextView) {
}
//结束编辑
func textViewDidEndEditing(_ textView: UITextView) {
}
//文本将要改变
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return true
}
//文本发生改变
func textViewDidChange(_ textView: UITextView) {
}
//焦点发生改变
func textViewDidChangeSelection(_ textView: UITextView) {
}
//是否允许对文本中的URL进行操作
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
return true
}
//是否允许对文本中的富文本进行操作
func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange) -> Bool {
return true
}
}
通知
extension NSNotification.Name {
public static let UITextViewTextDidBeginEditing: NSNotification.Name
public static let UITextViewTextDidChange: NSNotification.Name
public static let UITextViewTextDidEndEditing: NSNotification.Name
}
常用功能
1)UITextView显示边框
textView.layer.borderColor = UIColor.cyan.cgColor
textView.layer.borderWidth = 2.0
2)根据textView的内容计算textView的大小,参考
首先设置textView不可滚动,否则每次换行都会滚动一下
func addTextView() {
view.addSubview(textView)
textView.snp.makeConstraints { (make) in
make.left.top.right.equalToSuperview().inset(50)
make.height.equalTo(40)
}
textView.isScrollEnabled = false
}
然后在文本改变的代理方法中计算
//文本发生改变
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.infinity))
//更新高度约束
textView.snp.updateConstraints { (make) in
make.height.equalTo(newSize.height)
}
}
3)限制文字输入的个数,参考这里
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if(textView.text.count > 20 && range.length == 0) {
print("Please summarize in 20 characters or less")
return false
}
return true
}
或者使用如下方法进行更准确控制,输入到最大数量之后无法输入:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let selectedRange = textView.markedTextRange
var pos: UITextPosition? = nil
if let _sel = selectedRange {
pos = textView.position(from: _sel.start, offset: 0)
}
if selectedRange != nil, pos != nil {
let startOffset = textView.offset(from: textView.beginningOfDocument, to: selectedRange!.start)
if startOffset < maxCount {
return true
} else {
return false
}
}
let comcatStr = (textView.text as NSString).replacingCharacters(in: range, with: text)
let canInputLen = maxCount - comcatStr.length
if canInputLen >= 0 {
return true
} else {
let len = text.length + canInputLen
let rg = NSRange.init(location: 0, length: max(len, 0))
if rg.length > 0 {
var s = ""
if text.canBeConverted(to: .ascii) {
s = (text as NSString).substring(with: rg)
} else {
var idx = 0
var trimString = ""
(text as NSString).enumerateSubstrings(in: NSRange(location: 0, length: text.length), options: .byComposedCharacterSequences, using: { (subString, _, _, stop) in
if idx >= rg.length {
stop.pointee = true
return
}
trimString = (trimString as NSString).appending(subString ?? "")
idx += 1
})
s = trimString
}
textView.text = (textView.text as NSString).replacingCharacters(in: range, with: s)
}
return false
}
}
func textViewDidChange(_ textView: UITextView) {
let selectedRange = textView.markedTextRange
var pos: UITextPosition? = nil
if let _sel = selectedRange {
pos = textView.position(from: _sel.start, offset: 0)
}
if selectedRange != nil, pos != nil {
return
}
let textViewText: String = textView.text
let existTextNum = textViewText.length
if existTextNum > maxCount {
let s = (textViewText as NSString).substring(to: maxCount)
textView.text = s
}
}
4)添加默认文字placeholder
方法一,添加一个label,通过监听是否输入内容来控制是否显示
首先创建一个label
lazy var palceholderLabel: UILabel = {
let label = UILabel(frame: CGRect(origin: CGPoint(x: 5, y: 5), size: CGSize.zero))
label.text = "input some..."
label.textColor = UIColor.lightGray
label.sizeToFit()
return label
}()
添加到textView上
textView.addSubview(palceholderLabel)
根据输入的内容控制是否显示
func textViewDidChange(_ textView: UITextView) {
palceholderLabel.isHidden = !textView.text.isEmpty
}
其他的方式,可以看这里
5)自定义选择内容菜单栏
我们再看新闻的时候,常常在点选文字后会弹出菜单进行选择,复制等操作。这里我们也可以自己在菜单栏上添加一些其他内容,比如:分享到朋友圈,邮件。
func customMenu() {
let mail = UIMenuItem(title: "邮件", action: #selector(ViewController.onMail))
let weixin = UIMenuItem(title: "分享到朋友圈", action: #selector(ViewController.shareToWeiChat))
let menu = UIMenuController()
menu.menuItems = [mail,weixin]
}
@objc func onMail(){
print("mail")
}
@objc func shareToWeiChat(){
print("shareToWeiChat")
}
6)使用textView显示html内容,参考
func addHtml() {
let htmlString = "<html>" +
"<head>" +
"<style>" +
"body {" +
"background-color: rgb(230, 230, 230);" +
"font-family: 'Arial';" +
"text-decoration:none;" +
"}" +
"</style>" +
"</head>" +
"<body>" +
"<h1>A title</h1>" +
"<p>A paragraph</p>" +
"<b>bold text</b>" +
"</body></head></html>"
let htmlData = NSString(string: htmlString).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html]
let attributedString = try! NSAttributedString(data: htmlData!, options: options, documentAttributes: nil)
textView.attributedText = attributedString
}
7)获取选中的文本内容
//焦点发生改变
func textViewDidChangeSelection(_ textView: UITextView) {
if let selectedRange = textView.selectedTextRange {
let selectedText = textView.text(in: selectedRange)
}
}
8)修改光标的位置,主要是对selectedRange属性进行修改,设置开始的位置,如,从第三个文字开始显示光标
textView.selectedRange = NSRange(location: 3, length: 0)
textView.becomeFirstResponder()
9)为textView添加文字间距
如果是为静态显示的textView的内容设置行间距,操作方法跟label一样
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10
let attributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 20),
NSAttributedStringKey.paragraphStyle: paragraphStyle]
textView.attributedText = NSAttributedString(string: "人找到生活的意义才是幸福的。时间是大公无私的语言。", attributes: attributes)
对于动态输入,想要改变行间距,实现代理方法即可
func textViewDidChange(_ textView: UITextView) {
// 判断是否有候选字符,如果不为nil,代表有候选字符,那么不执行操作
if textView.markedTextRange == nil {
// 这里可以自行加判断,设置一次行间距即可,没必要反复设置
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10
let attributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 20),
NSAttributedStringKey.paragraphStyle: paragraphStyle]
textView.attributedText = NSAttributedString(string: textView.text, attributes: attributes)
}
}