iOS UITextView和UITextViewDelegate

时间:2020-02-23 14:45:58  来源:igfitidea点击:

在本教程中,我们将讨论UITextView元素,并在我们的应用程序中实现它的各种形式。

iOS UITextView

与它的名称不同,UITextView不仅仅是文本视图。
您可以对其进行编辑,键入,滚动。
UITextView是多行文本区域。
它具有内置的UIScrollView。

默认情况下,UITextView是可编辑的。
要禁用编辑,您需要将属性" isEditable"设置为" false"。

要以编程方式创建它,您需要创建一个指定宽度和高度的矩形:

let uiTextView = UITextView()
uiTextView.frame = CGRect(x: 0, y: 0, width: 200, height: 150)

UITextView与UITextField UITextView用于多行输入,而UITextField默认情况下仅用于单行。

默认情况下,UITextView不提供占位符/提示文本。

UITextViewDelegate

UITextViewDelegate协议定义了一组可选方法,这些方法在编辑文本时触发。
所有协议方法都是可选的。

以下是UITextViewDelegate中提供的一些方法。

textViewDidBeginEditing/textViewWillBeginEditingtextViewDidEndEditing/textViewWillEndEditingtextViewDidChange-在编辑文本时被调用。
textView(_ textView:UITextView,shouldChangeTextIn范围:NSRange,replaceText text:String)–返回一个布尔值,询问是否应替换文本。

一个有趣的用例是在UITextView上设置字符限制:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText newText: String) -> Bool {
      return textView.text.count + (newText.count - range.length) <= 140
  }

这将字符数限制设置为140。
就像Twitter!

UITextView的实现

创建一个新的XCode项目,开始吧:

在Main.storyboard中,将UITextView拖到ViewController上,并执行以下说明:

  • 在UITextView上设置自动布局约束。
    我们将其设置为固定高度的屏幕底部。

  • 通过助手编辑器使用IBOutlet将UITextView链接到ViewController.swift文件。

.

在模拟器和设备上运行应用程序后,我们得到:

那真是怪了!

键盘弹出UITextView上方。
单击返回时,键盘将关闭。

我们需要解决这些问题。

在您的ViewController.swift文件中添加以下代码:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

  @IBOutlet weak var bottomTextView: UITextView!
  override func viewDidLoad() {
      super.viewDidLoad()
      
      bottomTextView.delegate = self
      NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateTextView(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
      NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateTextView(notification:)), name: Notification.Name.UIKeyboardWillHide, object: nil)
  
  }
  
  func textViewDidBeginEditing(_ textView: UITextView) {
      textView.backgroundColor = UIColor.lightGray
  }
  
  func textViewDidEndEditing(_ textView: UITextView) {
      textView.backgroundColor = UIColor.white
  }
  
  func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
      if text == "\n" {
          textView.resignFirstResponder()
          return false
      }
      return true
  }
  
  @objc func updateTextView(notification: Notification)
  {
      if let userInfo = notification.userInfo
      {
          let keyboardFrameScreenCoordinates = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
          
          let keyboardFrame = self.view.convert(keyboardFrameScreenCoordinates, to: view.window)
          
          if notification.name == Notification.Name.UIKeyboardWillHide{
              view.frame.origin.y = 0
          }
          else{ 
              view.frame.origin.y = -keyboardFrame.height
          }
      }
  }
  

}

在上面的代码中,我们实现了UITextViewDelegate协议,实现了键盘关闭逻辑,并将UITextView移到了键盘上方。

  • 要在UITextView上进行设置,我们要做:bottomTextView.delegate = self
  • 我们已经实现了UITextViewDelegate的三个功能-" textViewDidBeginEditing"," textViewDidEndEditing"和" textView(shouldChangeTextIn :)"。
    在编辑开始和结束时,我们更改UITextView的背景颜色。

resignFirstResponder()用于关闭键盘。
为此,我们在UITextView上执行以下操作:

  • 在viewDidLoad中,我们添加了两个Notification观察器,它们可检测Keyboard中的更改并触发函数" updateTextView"。

  • 在" updateTextView"内部,我们根据通知名称更改UITextView的位置。

  • 为了将UITextView移动到键盘上方,我们以编程方式计算键盘的高度,然后将整个视图向上移动该高度。

现在运行应用程序时的输出为:

接下来,我们将研究自动调整UITextViews的大小

自动调整大小的UITextView

UITextViews的大小可以根据其内容大小进行更改。
让我们在情节提要中创建另一个ViewController并通过Button segue将其连接。

  • 将Button添加到当前的ViewController并设置约束。

  • 创建另一个ViewController场景,然后使用Ctrl +单击以拖动按钮来创建序列。
    创建一个新的Swift File SecondViewController.swift并在右窗格中设置名称

在SecondViewController.swift中,我们将以编程方式添加UITextView并通过Swift代码设置约束。

在下面的代码中,我们已经:

  • 在UITextView上添加了占位符

  • 键入更多内容时,会自动增加UITextView的高度。

  • 在UITextView上设置字体大小

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
      if text == "\n" {
          textView.resignFirstResponder()
          return false
      }
      return true
  }

textViewDidChange是UITextViewDelegate协议的一部分。
每当添加文本时,都会触发该事件。
每次我们计算文本的大小并增加UITextView的高度限制。

实际应用程序的输出为:

如您所见,UITextView的高度增加了。
但是,UITextView一直保持着上面的顶行。

这是由于ScrollBars。
我们可以通过在addAnotherTextView()函数中添加以下行来禁用它们:

import UIKit

class SecondViewController: UIViewController, UITextViewDelegate {
  let topTextView = UITextView()
  override func viewDidLoad() {
      super.viewDidLoad()
 
      addAnotherTextView()
      
  }
  
  func addAnotherTextView()  {
      
      topTextView.delegate = self
      topTextView.text = "Enter your notes here"
      topTextView.frame = CGRect(x: 0, y: 0, width: 200, height: 150)
      topTextView.font = .systemFont(ofSize: 20)
      
      view.addSubview(topTextView)
      topTextView.translatesAutoresizingMaskIntoConstraints = false
      [
          topTextView.topAnchor.constraint(equalTo: view!.safeAreaLayoutGuide.topAnchor),
          topTextView.leadingAnchor.constraint(equalTo: view!.leadingAnchor),
          topTextView.trailingAnchor.constraint(equalTo: view!.trailingAnchor),
          topTextView.heightAnchor.constraint(equalToConstant: 40)
          ].forEach{
              
``` sh
topTextView.isScrollEnabled = false
```.isActive = true
              
      }
  }
  
  
  
  func textViewDidBeginEditing(_ textView: UITextView) {
      textView.backgroundColor = UIColor.lightGray
      
      if (textView.text == "Enter your notes here")
      {
          textView.text = ""
          textView.textColor = .black
      }
      
  }
  
  func textViewDidEndEditing(_ textView: UITextView) {
      textView.backgroundColor = UIColor.white
      
      if (textView.text == "")
      {
          textView.text = "Enter your notes here"
          textView.textColor = .lightGray
      }
  }
  
  func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
      if text == "\n" {
          textView.resignFirstResponder()
          return false
      }
      
      return true
      
  }
  
  func textViewDidChange(_ textView: UITextView) {
      let size = CGSize(width: view.frame.width, height: .infinity)
      let approxSize = textView.sizeThatFits(size)
      
      textView.constraints.forEach{(constraint) in
          
          if constraint.firstAttribute == .height
          {
              constraint.constant = approxSize.height
          }
      }
  }    
}

现在,第一行并不会一直超出屏幕范围。

我们来看另一个用例。

自动调整UITextView的大小直到特定高度

我们可以调整UITextView的大小,使其只能扩展到特定的高度。

将您的textViewDidChange函数更改为:

func textViewDidChange(_ textView: UITextView)
  {
      if topTextView.contentSize.height >= 120.0
      {
          topTextView.isScrollEnabled = true
      }
      else
      {
          let size = CGSize(width: view.frame.width, height: .infinity)
          let approxSize = textView.sizeThatFits(size)
          
          textView.constraints.forEach {(constraint) in
              
                      if constraint.firstAttribute == .height{
                              constraint.constant = approxSize.height
                          }
                      }
          topTextView.isScrollEnabled = false
      }
  }

逻辑很简单:

每次增加高度时,请先检查是否达到最大高度。

如果是这样,就不再增加高度,只需启用滚动即可。
如果未达到最大高度,请禁用滚动条。