欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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)
        }
    }
}

效果如下:


iOS - UITextview的简单使用

常用属性


是否可以选中操作

textView.isSelectable = true

默认是true,可以选中,一旦设置为false,将不能够进行选中操作,默认可选中效果



iOS - UITextview的简单使用


富文本,可以通过设置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


iOS - UITextview的简单使用


输入视图

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
}


iOS - UITextview的简单使用


输入键盘附属视图

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
}
iOS - UITextview的简单使用



获得焦点后选中现有文本内容,输入内容时清除当前选中文本内容

textView.clearsOnInsertion = true

iOS - UITextview的简单使用


文本内容与边界的间距

textView.textContainerInset = UIEdgeInsetsMake(20, 20, 20, 20)

iOS - UITextview的简单使用


设置光标颜色

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

iOS - UITextview的简单使用

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)
      }
 }

iOS - UITextview的简单使用


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
}

iOS - UITextview的简单使用


其他的方式,可以看这里


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")
    }

iOS - UITextview的简单使用

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
 }

iOS - UITextview的简单使用


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()


iOS - UITextview的简单使用


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)
        }
  }