iOS UITextView和UITextViewDelegate

公羊信厚
2023-12-01

In this tutorial, we’ll be discussing the UITextView element and implement the various forms of it in our application.

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

iOS UITextView (iOS UITextView)

Unlike its name, a UITextView is not just a text view. You can edit it, type in it, scroll it.
A UITextView is a multiline text region. It has a built-in UIScrollView.

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

By default a UITextView is editable. To disabled editing you need to set the property isEditable as false.

默认情况下,UITextView是可编辑的。 要禁用编辑,您需要将isEditable属性isEditablefalse

To create it programmatically you need to create a rectangle with a width and height specified:

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

let uiTextView = UITextView()
uiTextView.frame = CGRect(x: 0, y: 0, width: 200, height: 150)
UITextView vs UITextField UITextView与UITextField
UITextView is for multi-line input whereas UITextField by default is for a single line only.
UITextView用于多行输入,而默认情况下,UITextField仅用于单行。

UITextView does not provide a placeholder/hint text by default.

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

UITextViewDelegate (UITextViewDelegate)

The UITextViewDelegate protocol defines a set of optional methods that gets triggered when the text is being edited. All the protocol methods are optional.

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

Following are some of the methods present in the UITextViewDelegate.

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

textViewDidBeginEditing/textViewWillBeginEditing
textViewDidEndEditing/textViewWillEndEditing
textViewDidChange – Gets called when the text is editted.
textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) – This returns a boolean which asks if the text should be replaced or not.

textViewDidBeginEditing / textViewWillBeginEditing
textViewDidEndEditing / textViewWillEndEditing
textViewDidChange –编辑文本时调用。
textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) –这将返回一个布尔值,询问是否应替换该文本。

An interesting use case would be to set the character limit on the UITextView:

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

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

This sets the character limit to 140. Just like twitter!

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

Enough talk. Lets code!

聊够了。 让代码!

UITextView的实现 (UITextView Implementation)

Create a new XCode project and let’s get started:

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

In the Main.storyboard drag the UITextView onto the ViewController and do the following instructions:

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

  1. Set auto-layout constraints on the UITextView. We’ve set it to the bottom of the screen with a fixed height.

    在UITextView上设置自动布局约束。 我们将其设置为固定高度的屏幕底部。
  2. Link the UITextView to the ViewController.swift file using the IBOutlet via Assistant Editor.

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

On running the application on the simulator and device we get:

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

That’s WEIRD!

那真是怪了!

The keyboard pops up over the UITextView.
On clicking return, the keyboard is getting dismissed.

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

We need to fix these.

我们需要解决这些问题。

Add the following code in your ViewController.swift file:

在您的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
            }
        }
    }
    

}

In the above code, we’ve implemented the UITextViewDelegate Protocol, implemented keyboard dismiss logic and moved the UITextView above the keyboard.

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

  1. To set it on the UITextView we do: bottomTextView.delegate = self

    要在UITextView上进行设置,请执行以下操作: bottomTextView.delegate = self
  2. We’ve implemented three functions of the UITextViewDelegatetextViewDidBeginEditing, textViewDidEndEditing, textView(shouldChangeTextIn:). We change the background color of the UITextView when editting begins and ends.
    resignFirstResponder() is used to dismiss the Keyboard. To do so on a UITextView we do:
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if text == "\n" {
                textView.resignFirstResponder()
                return false
            }
            return true
        }

    我们已经实现了UITextViewDelegate的三大功能- textViewDidBeginEditingtextViewDidEndEditingtextView(shouldChangeTextIn:) 。 在编辑开始和结束时,我们更改UITextView的背景颜色。
    resignFirstResponder()用于关闭键盘。 为此,我们在UITextView上执行以下操作:
  3. In the viewDidLoad, we’ve added two Notification observers which detect changes in Keyboard and trigger the function updateTextView.

    在viewDidLoad中,我们添加了两个Notification观察器,它们可检测Keyboard中的更改并触发功能updateTextView
  4. Inside the updateTextView we change the position of the UITextView depending on the notification name.

    updateTextView内部,我们根据通知名称更改UITextView的位置。
  5. To move the UITextView above the keyboard, we calculate the keyboard height programmatically and shift the whole view upwards by that height.

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

The output when the application is now run is:

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

Next, we’ll look into Auto-Sizing UITextViews

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

自动调整大小的UITextView (Auto-Size UITextView)

UITextViews size can be changed depending on the content size of it.
Let’s create another ViewController in our storyboard and connect it via a Button segue.

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

  1. Add the Button to the current ViewController and set the constraints.

    将Button添加到当前的ViewController并设置约束。
  2. Create another ViewController Scene and drag the Button using Ctrl+ Click to create a segue. Create a new Swift File SecondViewController.swift and set the name in the right pane

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

In the SecondViewController.swift, we’ll add the UITextView programmatically and set the constraints through Swift Code as well.

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

In the below code, we’ve:

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

  • Added Placeholders on the UITextView

    在UITextView上添加了占位符
  • Auto-increased the height of the UITextView when more content is typed.

    键入更多内容时,会自动增加UITextView的高度。
  • Set font size on the UITextView

    在UITextView上设置字体大小
  • 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{
                    $0.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
                }
            }
        }    
    }

    textViewDidChange is a part of the UITextViewDelegate protocol. This gets triggered whenever text is added.
    Each time we calculate the size of the text and increase the height constraint of the UITextView.

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

    The output of the application in action is:

    实际应用程序的输出为:

    As you can see the height of the UITextView is increased. But the UITextView keeps pushing the top line above.

    如您所见,UITextView的高度增加了。 但是,UITextView一直将上方推到最上方。

    This is because of the ScrollBars. We can disable them by adding the following line inside the addAnotherTextView() function:

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

    topTextView.isScrollEnabled = false

    Now the top line doesn’t keep going out of the screen.

    现在,最上面的一行不会一直显示在屏幕之外。

    Let’s look at another use case.

    让我们看看另一个用例。

    自动调整UITextView的大小直到特定高度 (Auto Sizing the UITextView till a specific height)

    We can size the UITextView such that it can expand only to a specific height.

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

    Change your textViewDidChange function to:

    将您的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
            }
        }

    The logic is pretty simple:

    逻辑很简单:

    If it is, don’t increase the height anymore and just enable the scrolling.
    If the max height isn’t reached, keep the scrollbars disabled.

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

    The output of the application in action is:

    实际应用程序的输出为:

    This brings an end to this tutorial on UITextView. We implement some practical scenarios that might help you in your iOS Development by using UITextViewDelegate and also Notification Observers.

    这样就结束了本教程的UITextView。 我们使用UITextViewDelegate以及Notification Observers来实现一些实用的方案,这些方案可能会在您的iOS开发中为您提供帮助。

    You can download the project from the link below:

    您可以从下面的链接下载项目:

    翻译自: https://www.journaldev.com/22238/ios-uitextview-and-uitextviewdelegate

 类似资料: