programing

Swift에서 UITextView에 자리 표시자 텍스트를 추가하시겠습니까?

powerit 2023. 4. 23. 11:33
반응형

Swift에서 UITextView에 자리 표시자 텍스트를 추가하시겠습니까?

holder이 in in에 홀더를 해야 하나요?UITextView 하면 '아예'로할 수 것과 UITextField、 。Swift

Swift 4용으로 업데이트됨

UITextView에 플레이스홀더 속성을 및 해야 합니다.UITextViewDelegate 아래의 # #중 하나를 것을 합니다.원하는 동작에 따라 아래 솔루션 #1 또는 #2 중 하나를 사용할 것을 권장합니다.

「: 」를 합니다.UITextViewDelegate하여 "Setting"을 설정합니다.textView.delegate = self이치노


솔루션 #1- 사용자가 텍스트 보기를 선택하는 즉시 자리 표시자를 지우려면:

번째로 '''를 설정합니다.UITextView하여 옅은 합니다.UITextField아! 쪽인가 하면, 「 」로 실행합니다.viewDidLoad★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

textView.text = "Placeholder"
textView.textColor = UIColor.lightGray

그런 다음 사용자가 텍스트 보기를 편집할 때 텍스트 보기에 자리 표시자가 포함된 경우(즉, 텍스트 색상이 밝은 회색인 경우) 자리 표시자 텍스트를 지우고 사용자의 입력을 수용할 수 있도록 텍스트 색상을 검은색으로 설정합니다.

func textViewDidBeginEditing(_ textView: UITextView) {
    if textView.textColor == UIColor.lightGray {
        textView.text = nil
        textView.textColor = UIColor.black
    }
}

그런 다음 사용자가 텍스트 보기 편집을 완료하고 첫 번째 응답자 역할을 포기하면, 텍스트 보기가 비어 있는 경우, 자리 표시자 텍스트를 다시 추가하고 해당 색상을 밝은 회색으로 설정하여 자리 표시자를 재설정하십시오.

func textViewDidEndEditing(_ textView: UITextView) {
    if textView.text.isEmpty {
        textView.text = "Placeholder"
        textView.textColor = UIColor.lightGray
    }
}

솔루션 #2- 텍스트 보기를 선택한 경우에도 텍스트 보기가 비어 있을 때마다 플레이스홀더를 표시하려면:

자리 해 주세요.viewDidLoad:

textView.text = "Placeholder"
textView.textColor = UIColor.lightGray

textView.becomeFirstResponder()

textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

(주의: OP에서는 텍스트 뷰가 로드되는 즉시 텍스트 뷰가 선택되도록 하고 싶었기 때문에 위의 코드에 텍스트 뷰 선택을 포함시켰습니다.이 동작이 바람직하지 않고 뷰 로드 시 텍스트뷰를 선택하지 않을 경우 위의 코드 청크에서 마지막 두 줄을 삭제하십시오.)

런음음 the 를 활용해주세요.shouldChangeTextInRange UITextViewDelegate다음과 같이 합니다.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    // Combine the textView text and the replacement text to
    // create the updated text string
    let currentText:String = textView.text
    let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)

    // If updated text view will be empty, add the placeholder
    // and set the cursor to the beginning of the text view
    if updatedText.isEmpty {

        textView.text = "Placeholder"
        textView.textColor = UIColor.lightGray

        textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
    }

    // Else if the text view's placeholder is showing and the
    // length of the replacement string is greater than 0, set 
    // the text color to black then set its text to the
    // replacement string
     else if textView.textColor == UIColor.lightGray && !text.isEmpty {
        textView.textColor = UIColor.black
        textView.text = text
    }

    // For every other case, the text should change with the usual
    // behavior...
    else {
        return true
    }

    // ...otherwise return false since the updates have already
    // been made
    return false
}

, 「」, 「」도 실장합니다.textViewDidChangeSelection홀더가되어 있는 하지 않도록 주의: "CHANGE" (CHANGE:textViewDidChangeSelection뷰가 로드되기 전에 호출되므로 창이 표시되는 경우에만 텍스트 뷰의 색상을 확인합니다).

func textViewDidChangeSelection(_ textView: UITextView) {
    if self.view.window != nil {
        if textView.textColor == UIColor.lightGray {
            textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
        }
    }
}

부동 자리 표시자


텍스트 뷰의 문자 수에 대한 변경을 추적하여 텍스트 뷰 위에 자리 표시자 레이블을 배치하고 글꼴, 색상을 설정하고 자리 표시자 가시성을 관리하는 것은 간단하고 안전하며 신뢰할 수 있습니다.

업데이트: 23년 2월 10일 @RakshithaMurangaRodrigo에 의한 제안 통합 코멘트

Swift 5:

class NotesViewController : UIViewController {

    @IBOutlet var textView : UITextView!
    var placeholderLabel : UILabel!
        
    override func viewDidLoad() {
        super.viewDidLoad()
    
        textView.delegate = self
        placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = .italicSystemFont(ofSize: (textView.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        textView.addSubview(placeholderLabel)
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
        placeholderLabel.textColor = .tertiaryLabel
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
}

extension NotesViewController : UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        placeholderLabel?.isHidden = !textView.text.isEmpty
    }
    func textViewDidEndEditing(_ textView: UITextView) {         
        placeholderLabel?.isHidden = !textView.text.isEmpty     
    }  
    func textViewDidBeginEditing(_ textView: UITextView) {         
        placeholderLabel?.isHidden = true     
    }
}

신속:

텍스트 뷰를 프로그래밍 방식으로 추가하거나 Interface Builder를 통해 추가합니다(마지막인 경우).

@IBOutlet weak var yourTextView: UITextView!

위임자(UITextViewDelegate)를 추가하십시오.

class ViewController: UIViewController, UITextViewDelegate {

viewDidLoad 메서드에서 다음을 추가합니다.

override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    yourTextView.delegate = self
    yourTextView.text = "Placeholder text goes right here..."
    yourTextView.textColor = UIColor.lightGray

이제 매직 파트를 소개하고 다음 기능을 추가합니다.

func textViewDidBeginEditing(_ textView: UITextView) {

    if yourTextView.textColor == UIColor.lightGray {
        yourTextView.text = ""
        yourTextView.textColor = UIColor.black
    }
}

편집이 시작될 때마다 이 작업이 수행되므로 색상 속성을 사용하여 상태를 알려주는 조건을 확인합니다.를 ""로 설정"nil추천하지 않습니다.그 직후에, 텍스트의 색을 희망(이 경우는 검정)으로 설정합니다.

이제 이 기능도 추가합니다.

func textViewDidEndEditing(_ textView: UITextView) {

    if yourTextView.text == "" {

        yourTextView.text = "Placeholder text ..."
        yourTextView.textColor = UIColor.lightGray
    }
}

말씀드리지만, 가가 to to to to to to to to to to to to to와 .nil저는 이미 그것을 시도했지만, 그것은 효과가 없습니다. 값을 스타일로 다시 합니다. 왜냐하면 이 조건이기 때문입니다.이것은 체크인 조건이기 때문입니다.textViewDidBeginEditing.

도 언급하지 .NSTextStorageDelegateUITextViewDelegate텍스트설정 text대리 메서드는 호출되지 않으므로 사용자가 직접 자리 표시자의 가시성을 설정해야 합니다.

,에서는NSTextStorageDelegate의 »textStorage(_:didProcessEditing:range:changeInLength:) 어떠한 됩니다.뭇매를 맞다

textView.textStorage.delegate = self

(인)UITextView이 위임 속성은 다음과 같습니다.nil디폴트 동작에는 영향을 주지 않습니다.)

을 것 combine combine combine combine combine combine combine combine combine combine combine combine combine.UILabel @는, 「@clearlight」의 전체를 랩 할 수 .UITextView의 »placeholder실장할 수 있습니다.

extension UITextView {

    private class PlaceholderLabel: UILabel { }

    private var placeholderLabel: PlaceholderLabel {
        if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
            return label
        } else {
            let label = PlaceholderLabel(frame: .zero)
            label.font = font
            addSubview(label)
            return label
        }
    }

    @IBInspectable
    var placeholder: String {
        get {
            return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
        }
        set {
            let placeholderLabel = self.placeholderLabel
            placeholderLabel.text = newValue
            placeholderLabel.numberOfLines = 0
            let width = frame.width - textContainer.lineFragmentPadding * 2
            let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
            placeholderLabel.frame.size.height = size.height
            placeholderLabel.frame.size.width = width
            placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)

            textStorage.delegate = self
        }
    }

}

extension UITextView: NSTextStorageDelegate {

    public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) {
        if editedMask.contains(.editedCharacters) {
            placeholderLabel.isHidden = !text.isEmpty
        }
    }

}

private( 완료)라고 하는 프라이빗에 주의해 .PlaceholderLabel 홀더 라벨을 할 수 있는 홀더 라벨은 플레이스 홀더 라벨을 사용하는 이 있습니다이것은, FD를 사용하는 것보다 훨씬 「신속한」 것입니다.tag★★★★★★★★★★★★★★★★★★.

을 사용해도 할 수 .UITextView다른 사람에게요

텍스트 보기의 클래스를 변경할 필요도 없습니다.을 모든 플레이스 홀더에 할 수 .UITextView인터페이스 빌더

의 실장은 생략했습니다.placeholderColor할 수 , 이 은 "Calculated "와 하여 몇 만 더 할 수 .placeholder.

중 몇으로 다음과 인터페이스 빌더 할 수 .UITextView 명령어 우이 , ,:

  • 가능한 텍스트가 포함되어 있습니다.이 「 」의 .UITextField.
  • 추가 서브뷰나 제약이 필요 없습니다.
  • View Controller의 위임이나 기타 동작이 필요하지 않습니다.
  • 알림이 필요 없습니다.
  • 를 보고 합니다.text★★★★★★★★★★★★★★★★★★.

특히 iOS의 플레이스 홀더 색상을 하드 코딩하지 않고 프로그램적으로 끌어낼 수 있는 방법이 있다면 어떤 개선 제안도 환영입니다.

Swift v5:

import UIKit
@IBDesignable class TextViewWithPlaceholder: UITextView {
    
    override var text: String! { // Ensures that the placeholder text is never returned as the field's text
        get {
            if showingPlaceholder {
                return "" // When showing the placeholder, there's no real text to return
            } else { return super.text }
        }
        set { super.text = newValue }
    }
    @IBInspectable var placeholderText: String = ""
    @IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) // Standard iOS placeholder color (#C7C7CD). See https://stackoverflow.com/questions/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
    private var showingPlaceholder: Bool = true // Keeps track of whether the field is currently showing a placeholder
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        if text.isEmpty {
            showPlaceholderText() // Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
        }
    }
    
    override func becomeFirstResponder() -> Bool {
        // If the current text is the placeholder, remove it
        if showingPlaceholder {
            text = nil
            textColor = nil // Put the text back to the default, unmodified color
            showingPlaceholder = false
        }
        return super.becomeFirstResponder()
    }
    
    override func resignFirstResponder() -> Bool {
        // If there's no text, put the placeholder back
        if text.isEmpty {
            showPlaceholderText()
        }
        return super.resignFirstResponder()
    }
    
    private func showPlaceholderText() {
        showingPlaceholder = true
        textColor = placeholderTextColor
        text = placeholderText
    }
}

두 가지 다른 텍스트 보기를 사용하여 이 작업을 수행했습니다.

  1. 자리 표시자로 사용되는 배경의 하나.
  2. 사용자가 실제로 입력하는 포그라운드(투명 배경)의 하나.

사용자가 전경 뷰에 내용을 입력하기 시작하면 배경의 자리 표시자가 사라집니다(사용자가 모든 내용을 삭제하면 다시 나타납니다).따라서 단일 줄 텍스트 필드의 자리 표시자와 동일하게 작동합니다.

여기 제가 사용한 코드가 있습니다.descriptionField는 사용자가 입력하는 필드이고 descriptionPlaceholder는 백그라운드에서 입력하는 필드입니다.

func textViewDidChange(descriptionField: UITextView) {
    if descriptionField.text.isEmpty == false {
        descriptionPlaceholder.text = ""
    } else {
        descriptionPlaceholder.text = descriptionPlaceholderText
    }
}

는 클리어라이트의 대답으로 코드를 편리하게 하려고 노력했다.

extension UITextView{

    func setPlaceholder() {

        let placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        placeholderLabel.tag = 222
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !self.text.isEmpty

        self.addSubview(placeholderLabel)
    }

    func checkPlaceholder() {
        let placeholderLabel = self.viewWithTag(222) as! UILabel
        placeholderLabel.isHidden = !self.text.isEmpty
    }

}

사용.

override func viewDidLoad() {
    textView.delegate = self
    textView.setPlaceholder()
}

func textViewDidChange(_ textView: UITextView) {
    textView.checkPlaceholder()
}

이게 내가 이 일을 완수하기 위해 사용하는 것이다.

@IBDesignable class UIPlaceholderTextView: UITextView {
    
    var placeholderLabel: UILabel?
    
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        sharedInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        sharedInit()
    }
    
    override func prepareForInterfaceBuilder() {
        sharedInit()
    }
    
    func sharedInit() {
        refreshPlaceholder()
        NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: UITextView.textDidChangeNotification, object: nil)
    }

    @IBInspectable var placeholder: String? {
        didSet {
            refreshPlaceholder()
        }
    }

    @IBInspectable var placeholderColor: UIColor? = .darkGray {
        didSet {
            refreshPlaceholder()
        }
    }
    
    @IBInspectable var placeholderFontSize: CGFloat = 14 {
        didSet {
            refreshPlaceholder()
        }
    }
    
    func refreshPlaceholder() {
        if placeholderLabel == nil {
            placeholderLabel = UILabel()
            let contentView = self.subviews.first ?? self
            
            contentView.addSubview(placeholderLabel!)
            placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false
            
            placeholderLabel?.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: textContainerInset.left + 4).isActive = true
            placeholderLabel?.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: textContainerInset.right + 4).isActive = true
            placeholderLabel?.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textContainerInset.top).isActive = true
            placeholderLabel?.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: textContainerInset.bottom).isActive = true
        }
        placeholderLabel?.text = placeholder
        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.font = UIFont.systemFont(ofSize: placeholderFontSize)
    }
    
    @objc func textChanged() {
        if self.placeholder?.isEmpty ?? true {
            return
        }
        
        UIView.animate(withDuration: 0.25) {
            if self.text.isEmpty {
                self.placeholderLabel?.alpha = 1.0
            } else {
                self.placeholderLabel?.alpha = 0.0
            }
        }
    }
    
    override var text: String! {
        didSet {
            textChanged()
        }
    }

}

이와 유사한 접근법이 몇 가지 있다는 것을 알지만, 이 접근법의 이점은 다음과 같습니다.

  • IB에서 자리 표시자 텍스트, 글꼴 크기 및 색상을 설정합니다.
  • IB에서 "Scroll View에 스크롤 가능한 콘텐츠가 모호합니다"라는 경고가 더 이상 표시되지 않습니다.
  • 자리 표시자 표시/숨김에 애니메이션을 추가합니다.

신속:

를를 add add add add add 를 추가하다TextView @IBOutlet:

@IBOutlet weak var txtViewMessage: UITextView!

서서 viewWillAppear

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    txtViewMessage.delegate = self    // Give TextViewMessage delegate Method
    
    txtViewMessage.text = "Place Holder Name"
    txtViewMessage.textColor = UIColor.lightGray
}

★★★★★★★★★★★★★★★를 추가해 주세요.Delegate(UITextViewDelegate):

// MARK: - UITextViewDelegate
extension ViewController: UITextViewDelegate {

    func textViewDidBeginEditing(_ textView: UITextView) {

        if !txtViewMessage.text!.isEmpty && txtViewMessage.text! == "Place Holder Name" {
            txtViewMessage.text = ""
            txtViewMessage.textColor = UIColor.black
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
    
        if txtViewMessage.text.isEmpty {
            txtViewMessage.text = "Place Holder Name"
            txtViewMessage.textColor = UIColor.lightGray
        }
    }
}

뷰 로드에서의 SET 값

    txtVw!.autocorrectionType = UITextAutocorrectionType.No
    txtVw!.text = "Write your Placeholder"
    txtVw!.textColor = UIColor.lightGrayColor()



func textViewDidBeginEditing(textView: UITextView) {
    if (txtVw?.text == "Write your Placeholder")

    {
        txtVw!.text = nil
        txtVw!.textColor = UIColor.blackColor()
    }
}

func textViewDidEndEditing(textView: UITextView) {
    if txtVw!.text.isEmpty
    {
        txtVw!.text = "Write your Placeholder"
        txtVw!.textColor = UIColor.lightGrayColor()
    }
    textView.resignFirstResponder()
}

또 하나의 솔루션 (Swift 3) :

import UIKit

protocol PlaceholderTextViewDelegate {
    func placeholderTextViewDidChangeText(_ text:String)
    func placeholderTextViewDidEndEditing(_ text:String)
}

final class PlaceholderTextView: UITextView {

    var notifier:PlaceholderTextViewDelegate?

    var placeholder: String? {
        didSet {
            placeholderLabel?.text = placeholder
        }
    }
    var placeholderColor = UIColor.lightGray
    var placeholderFont = UIFont.appMainFontForSize(14.0) {
        didSet {
            placeholderLabel?.font = placeholderFont
        }
    }

    fileprivate var placeholderLabel: UILabel?

    // MARK: - LifeCycle

    init() {
        super.init(frame: CGRect.zero, textContainer: nil)
        awakeFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.delegate = self
        NotificationCenter.default.addObserver(self, selector: #selector(PlaceholderTextView.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: nil)

        placeholderLabel = UILabel()
        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.text = placeholder
        placeholderLabel?.textAlignment = .left
        placeholderLabel?.numberOfLines = 0
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        placeholderLabel?.font = placeholderFont

        var height:CGFloat = placeholderFont.lineHeight
        if let data = placeholderLabel?.text {

            let expectedDefaultWidth:CGFloat = bounds.size.width
            let fontSize:CGFloat = placeholderFont.pointSize

            let textView = UITextView()
            textView.text = data
            textView.font = UIFont.appMainFontForSize(fontSize)
            let sizeForTextView = textView.sizeThatFits(CGSize(width: expectedDefaultWidth,
                                                               height: CGFloat.greatestFiniteMagnitude))
            let expectedTextViewHeight = sizeForTextView.height

            if expectedTextViewHeight > height {
                height = expectedTextViewHeight
            }
        }

        placeholderLabel?.frame = CGRect(x: 5, y: 0, width: bounds.size.width - 16, height: height)

        if text.isEmpty {
            addSubview(placeholderLabel!)
            bringSubview(toFront: placeholderLabel!)
        } else {
            placeholderLabel?.removeFromSuperview()
        }
    }

    func textDidChangeHandler(notification: Notification) {
        layoutSubviews()
    }

}

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

    func textViewDidChange(_ textView: UITextView) {
        notifier?.placeholderTextViewDidChangeText(textView.text)
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        notifier?.placeholderTextViewDidEndEditing(textView.text)
    }
}

결과

여기에 이미지 설명 입력

는 pod pod를 할 수 .IQKeyboardManagerSwift.

  1. .IQTextViewTextView를 누릅니다
  2. .IQKeyboardManagerSwift
  3. 으로 꼭 한 콘센트를 .textView[/ // 를
  4. 주다textView 일부 검사

다음과 같은 간단한 솔루션을 이용할 수 있습니다.

@IBDesignable
class PlaceHolderTextView: UITextView {

    @IBInspectable var placeholder: String = "" {
         didSet{
             updatePlaceHolder()
        }
    }

    @IBInspectable var placeholderColor: UIColor = UIColor.gray {
        didSet {
            updatePlaceHolder()
        }
    }

    private var originalTextColor = UIColor.darkText
    private var originalText: String = ""

    private func updatePlaceHolder() {

        if self.text == "" || self.text == placeholder  {

            self.text = placeholder
            self.textColor = placeholderColor
            if let color = self.textColor {

                self.originalTextColor = color
            }
            self.originalText = ""
        } else {
            self.textColor = self.originalTextColor
            self.originalText = self.text
        }

    }

    override func becomeFirstResponder() -> Bool {
        let result = super.becomeFirstResponder()
        self.text = self.originalText
        self.textColor = self.originalTextColor
        return result
    }
    override func resignFirstResponder() -> Bool {
        let result = super.resignFirstResponder()
        updatePlaceHolder()

        return result
    }
}

스위프트 3.2

extension EditProfileVC:UITextViewDelegate{

    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.textColor == UIColor.lightGray {
            textView.text = nil
            textView.textColor = UIColor.black
       }
    }
    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.isEmpty {
            textView.text = "Placeholder"
            textView.textColor = UIColor.lightGray
        }
    }
}

처음에 사용자가 textViewDidBeginiting 호출을 편집하고 text 회색의 색상이 사용자가 아무것도 쓰지 않았음을 의미하는지 확인한 후 textview nero로 설정하고 사용자가 문자를 보낼 때 색상을 검은색으로 변경합니다.

사용자가 textViewDidEndedEditing을 호출하여 textview에 아무것도 쓰지 않았는지 확인한 후 "PlaceHolder" 텍스트와 함께 회색으로 설정됩니다.

이 문제를 해결하는 방법(Swift 4):

를 사용할 수 있고, 홀더 크기에 를 조정할 수 , holders size size른 aa a a a a a a a a a a, the the a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a를 덮어쓰지 않는 가장 간단한 솔루션을 만드는 것이 였습니다.delegate, 모든 것을 하고 있다UITextView이치노

import UIKit

class PlaceholderTextView: UITextView {
    var placeholderColor: UIColor = .lightGray
    var defaultTextColor: UIColor = .black

    private var isShowingPlaceholder = false {
        didSet {
            if isShowingPlaceholder {
                text = placeholder
                textColor = placeholderColor
            } else {
                textColor = defaultTextColor
            }
        }
    }

    var placeholder: String? {
        didSet {
            isShowingPlaceholder = !hasText
        }
    }

    @objc private func textViewDidBeginEditing(notification: Notification) {
        textColor = defaultTextColor
        if isShowingPlaceholder { text = nil }
    }

    @objc private func textViewDidEndEditing(notification: Notification) {
        isShowingPlaceholder = !hasText
    }

    // MARK: - Construction -
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup() {
        NotificationCenter.default.addObserver(self, selector: #selector(textViewDidBeginEditing(notification:)), name: UITextView.textDidBeginEditingNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(textViewDidEndEditing(notification:)), name: UITextView.textDidEndEditingNotification, object: nil)
    }

    // MARK: - Destruction -
    deinit { NotificationCenter.default.removeObserver(self) }
}

신속한 회답

여기 자리 표시자를 애니메이션으로 만드는 커스텀 클래스가 있습니다.

class CustomTextView: UITextView {
    
    //   MARK: - public
    
    public var placeHolderText: String? = "Enter Reason.."
    
    public lazy var placeHolderLabel: UILabel! = {
        let placeHolderLabel = UILabel(frame: .zero)
        placeHolderLabel.numberOfLines = 0
        placeHolderLabel.backgroundColor = .clear
        placeHolderLabel.alpha = 0.5
        return placeHolderLabel
    }()
    
    //   MARK: - Init
    
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        enableNotifications()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        enableNotifications()
    }
    
    func setup() {
        placeHolderLabel.frame = CGRect(x: 8, y: 8, width: self.bounds.size.width - 16, height: 15)
        placeHolderLabel.sizeToFit()
    }
    
    //   MARK: - Cycle
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        textContainerInset = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 8)
        returnKeyType = .done
        addSubview(placeHolderLabel)
        placeHolderLabel.frame = CGRect(x: 8, y: 8, width: self.bounds.size.width - 16, height: 15)
        placeHolderLabel.textColor = textColor
        placeHolderLabel.font = font
        placeHolderLabel.text = placeHolderText
        bringSubviewToFront(placeHolderLabel)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    
    //   MARK: - Notifications
    
    private func enableNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(textDidChangeNotification(_:)), name: UITextView.textDidChangeNotification , object: nil)
    }
    
    @objc func textDidChangeNotification(_ notify: Notification) {
        guard self == notify.object as? UITextView else { return }
        guard placeHolderText != nil else { return }
        
        UIView.animate(withDuration: 0.25, animations: {
            self.placeHolderLabel.alpha = (self.text.count == 0) ? 0.5 : 0
        }, completion: nil)
    }
    
}

왜 사람들이 이 문제를 그렇게 복잡하게 만드는지 모르겠어요.그것은 꽤 간단하고 간단하다.다음은 요청된 기능을 제공하는 UITextView의 하위 클래스입니다.

- (void)customInit
{
    self.contentMode = UIViewContentModeRedraw;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

    - (void)textChanged:(NSNotification *)notification
    {
        if (notification.object == self) {
            if(self.textStorage.length != 0 || !self.textStorage.length) {
                [self setNeedsDisplay];
            }
        }
    }


    #pragma mark - Setters

    - (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font
    {
        self.placeholderText = placeholderText;
        self.placeholderTextFont = font;

    }



    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        [[UIColor lightGrayColor] setFill];

        if (self.textStorage.length != 0) {
            return;
        }

        CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView
        NSDictionary *attributes =  @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]};
        [self.placeholderText drawInRect:inset withAttributes:attributes];
    }`

여러 텍스트 보기로 작업하는 경우 이 솔루션을 사용할 수 있습니다.

func textViewShouldBeginEditing(textView: UITextView) -> Bool {        
    // Set cursor to the beginning if placeholder is set
    if textView.textColor == UIColor.lightGrayColor() {
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }

    return true
}

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Remove placeholder
    if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 {
        textView.text = ""
        textView.textColor = UIColor.blackColor()
    }

    if text == "\n" {
        textView.resignFirstResponder()
        return false
    }

    return true
}

func textViewDidChange(textView: UITextView) {
    // Set placeholder if text is empty
    if textView.text.isEmpty {
        textView.text = NSLocalizedString("Hint", comment: "hint")
        textView.textColor = UIColor.lightGrayColor()
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }
}

func textViewDidChangeSelection(textView: UITextView) {
    // Set cursor to the beginning if placeholder is set
    let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)

    // Do not change position recursively
    if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition {
        textView.selectedTextRange = firstPosition
    }
}

Swift - UITextView를 상속받은 클래스를 작성하고 플레이스 홀더 역할을 하기 위해 서브뷰로 UILabel을 추가했습니다.

  import UIKit
  @IBDesignable
  class HintedTextView: UITextView {

      @IBInspectable var hintText: String = "hintText" {
          didSet{
              hintLabel.text = hintText
          }
      }

      private lazy var hintLabel: UILabel = {
          let label = UILabel()
          label.font = UIFont.systemFontOfSize(16)
          label.textColor = UIColor.lightGrayColor()
          label.translatesAutoresizingMaskIntoConstraints = false
          return label
      }()


      override init(frame: CGRect, textContainer: NSTextContainer?) {
          super.init(frame: frame, textContainer: textContainer)
          setupView()
      }

      required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
         setupView()
      }

      override func prepareForInterfaceBuilder() {
         super.prepareForInterfaceBuilder()
         setupView()
      }

      private func setupView() {

        translatesAutoresizingMaskIntoConstraints = false
        delegate = self
        font = UIFont.systemFontOfSize(16)

        addSubview(hintLabel)

        NSLayoutConstraint.activateConstraints([

           hintLabel.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 4),
           hintLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: 8),
           hintLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4),
           hintLabel.heightAnchor.constraintEqualToConstant(30)
         ])
        }

      override func layoutSubviews() {
        super.layoutSubviews()
        setupView()
     }

}

스위프트 3.1

이 확장은 저에게 있어서 매우 효과적이었습니다.https://github.com/devxoul/UITextView-Placeholder

코드 스니펫을 다음에 나타냅니다.

팟을 통해 설치:

pod 'UITextView+Placeholder', '~> 1.2'

클래스로 가져오기

import UITextView_Placeholder

리리 and and를 추가한다.placeholder한 「」의 .UITextView

textView.placeholder = "Put some detail"

★★★★★★★★★★★★... 번째 는 ( ( ) )입니다.UITextView) 。

편집이 완료되면 자리 표시자 텍스트를 다시 표시하기 위해 큐를 디스패치해야 했습니다.

func textViewDidBeginEditing(_ textView: UITextView) {

    if textView.text == "Description" {
        textView.text = nil
    }
}

func textViewDidEndEditing(_ textView: UITextView) {

    if textView.text.isEmpty {
        DispatchQueue.main.async {
            textView.text = "Description"
        }
    }
}

Swift 4, 4.2 및 5

[![@IBOutlet var detailTextView: UITextView!

override func viewDidLoad() {
        super.viewDidLoad()
        detailTextView.delegate = self
}

extension ContactUsViewController : UITextViewDelegate {

    public func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == "Write your message here..." {
            detailTextView.text = ""
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.86)

        }
        textView.becomeFirstResponder()
    }

    public func textViewDidEndEditing(_ textView: UITextView) {

        if textView.text == "" {
            detailTextView.text = "Write your message here..."
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.30)
        }
        textView.resignFirstResponder()
    }
[![}][1]][1]

이 게시물의 모든 답변과 달리UITextView 플레이스 홀더 속성이 있습니다.제가 이해할 수 없는 이유로 IB에서만 노출됩니다.

<userDefinedRuntimeAttributes>
  <userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>

따라서 스토리보드를 사용하고 있으며 정적 플레이스홀더로도 충분할 경우 인스펙터에 속성을 설정합니다.

이 속성은 다음과 같이 코드로 설정할 수도 있습니다.

textView.setValue("My Placeholder", forKeyPath: "placeholder")

날씨가 흐려져 있기 때문에 개인 API를 통해 접근합니다.

저는 이 방법으로 제출해 본 적이 없습니다.하지만 곧 이 방법으로 제출하고 그에 따라 이 답변을 업데이트하겠습니다.

갱신:

저는 이 코드를 Apple에서 문제없이 여러 릴리스로 발송했습니다.

업데이트: 이 기능은 Xcode 11.2 이전에서만 작동합니다.

스위프트 5.2

스탠드아론 클래스

어디서든 사용할 수 있는 클래스를 원하는 경우 이 옵션을 사용하십시오.

import UIKit
class PlaceHolderTextView:UITextView, UITextViewDelegate{
var placeholderText = "placeholderText"

override func willMove(toSuperview newSuperview: UIView?) {
    textColor = .lightText
    delegate = self
}

func textViewDidBeginEditing(_ textView: UITextView) {
    if textView.text == placeholderText{
        placeholderText = textView.text
        textView.text = ""
        textView.textColor = .darkText
    }
}

func textViewDidEndEditing(_ textView: UITextView) {
    if textView.text == ""{
        textView.text = placeholderText
        textColor = .lightText
    }
}    
}

서의 열쇠는 '열쇠'입니다.willMove(toSuperView:) 수 in ).ViewDidLoad/View가 표시됩니다.

서드파티 라이브러리를 추가할 필요가 없습니다.아래 코드를 사용하세요...

class SubmitReviewVC : UIViewController, UITextViewDelegate {

@IBOutlet var txtMessage : UITextView!
var lblPlaceHolder : UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    txtMessage.delegate = self
    lblPlaceHolder = UILabel()
    lblPlaceHolder.text = "Enter message..."
    lblPlaceHolder.font = UIFont.systemFont(ofSize: txtMessage.font!.pointSize)
    lblPlaceHolder.sizeToFit()
    txtMessage.addSubview(lblPlaceHolder)
    lblPlaceHolder.frame.origin = CGPoint(x: 5, y: (txtMessage.font?.pointSize)! / 2)
    lblPlaceHolder.textColor = UIColor.lightGray
    lblPlaceHolder.isHidden = !txtMessage.text.isEmpty
}

func textViewDidChange(_ textView: UITextView) {
    lblPlaceHolder.isHidden = !textView.text.isEmpty
}

}

IOS에는 TextView에 플레이스홀더를 직접 추가하는 속성이 없습니다.라벨을 추가하고 textView 변경 내용을 표시/숨길 수 있습니다.SWIFT 2.0을 사용하여 textview 위임장을 구현하십시오.

func textViewDidChange(TextView: UITextView)
{

 if  txtShortDescription.text == ""
    {
        self.lblShortDescription.hidden = false
    }
    else
    {
        self.lblShortDescription.hidden = true
    }

}

@nerdistist ner @ @ @ @ @ @ @ @ @ 。으로, 저는 '연장', '연장', '연장', '연장'으로.UITextView:

import Foundation
import UIKit

extension UITextView
{
  private func add(_ placeholder: UILabel) {
    for view in self.subviews {
        if let lbl = view as? UILabel  {
            if lbl.text == placeholder.text {
                lbl.removeFromSuperview()
            }
        }
    }
    self.addSubview(placeholder)
  }

  func addPlaceholder(_ placeholder: UILabel?) {
    if let ph = placeholder {
      ph.numberOfLines = 0  // support for multiple lines
      ph.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
      ph.sizeToFit()
      self.add(ph)
      ph.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
      ph.textColor = UIColor(white: 0, alpha: 0.3)
      updateVisibility(ph)
    }
  }

  func updateVisibility(_ placeHolder: UILabel?) {
    if let ph = placeHolder {
      ph.isHidden = !self.text.isEmpty
    }
  }
}

예를 들어 ViewController 클래스에서 사용하는 방법은 다음과 같습니다.

class MyViewController: UIViewController, UITextViewDelegate {
  private var notePlaceholder: UILabel!
  @IBOutlet weak var txtNote: UITextView!
  ...
  // UIViewController
  override func viewDidLoad() {
    notePlaceholder = UILabel()
    notePlaceholder.text = "title\nsubtitle\nmore..."
    txtNote.addPlaceholder(notePlaceholder)
    ...
  }

  // UITextViewDelegate
  func textViewDidChange(_ textView: UITextView) {
    txtNote.updateVisbility(notePlaceholder)
    ...
  }

UITextview 플레이스홀더!

여기에 이미지 설명 입력

갱신:

텍스트 뷰의 코드 텍스트를 변경할 경우 updateVisibitly 메서드를 호출하여 플레이스 홀더를 숨깁니다.

txtNote.text = "something in code"
txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.

되는 것을 하기 위해 플레이스 홀더를 합니다.add()되어 있습니다.extension.

swift2로.2:

public class CustomTextView: UITextView {

private struct Constants {
    static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()

private var placeholderLabelConstraints = [NSLayoutConstraint]()

@IBInspectable public var placeholder: String = "" {
    didSet {
        placeholderLabel.text = placeholder
    }
}

@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
    didSet {
        placeholderLabel.textColor = placeholderColor
    }
}

override public var font: UIFont! {
    didSet {
        placeholderLabel.font = font
    }
}

override public var textAlignment: NSTextAlignment {
    didSet {
        placeholderLabel.textAlignment = textAlignment
    }
}

override public var text: String! {
    didSet {
        textDidChange()
    }
}

override public var attributedText: NSAttributedString! {
    didSet {
        textDidChange()
    }
}

override public var textContainerInset: UIEdgeInsets {
    didSet {
        updateConstraintsForPlaceholderLabel()
    }
}

override public init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    commonInit()
}

required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
}

private func commonInit() {
    NSNotificationCenter.defaultCenter().addObserver(self,
                                                     selector: #selector(textDidChange),
                                                     name: UITextViewTextDidChangeNotification,
                                                     object: nil)

    placeholderLabel.font = font
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
    placeholderLabel.text = placeholder
    placeholderLabel.numberOfLines = 0
    placeholderLabel.backgroundColor = UIColor.clearColor()
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(placeholderLabel)
    updateConstraintsForPlaceholderLabel()
}

private func updateConstraintsForPlaceholderLabel() {
    var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
                                                                        options: [],
                                                                        metrics: nil,
                                                                        views: ["placeholder": placeholderLabel])
    newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(\(textContainerInset.top))-[placeholder]",
                                                                     options: [],
                                                                     metrics: nil,
                                                                     views: ["placeholder": placeholderLabel])
    newConstraints.append(NSLayoutConstraint(
        item: placeholderLabel,
        attribute: .Width,
        relatedBy: .Equal,
        toItem: self,
        attribute: .Width,
        multiplier: 1.0,
        constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
        ))
    removeConstraints(placeholderLabelConstraints)
    addConstraints(newConstraints)
    placeholderLabelConstraints = newConstraints
}

@objc private func textDidChange() {
    placeholderLabel.hidden = !text.isEmpty
}

public override func layoutSubviews() {
    super.layoutSubviews()
    placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self,
                                                        name: UITextViewTextDidChangeNotification,
                                                        object: nil)
}

}

신속한3:

import UIKit

클래스 커스텀Text View: UIText View {

private struct Constants {
    static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()

private var placeholderLabelConstraints = [NSLayoutConstraint]()

@IBInspectable public var placeholder: String = "" {
    didSet {
        placeholderLabel.text = placeholder
    }
}

@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
    didSet {
        placeholderLabel.textColor = placeholderColor
    }
}

override public var font: UIFont! {
    didSet {
        placeholderLabel.font = font
    }
}

override public var textAlignment: NSTextAlignment {
    didSet {
        placeholderLabel.textAlignment = textAlignment
    }
}

override public var text: String! {
    didSet {
        textDidChange()
    }
}

override public var attributedText: NSAttributedString! {
    didSet {
        textDidChange()
    }
}

override public var textContainerInset: UIEdgeInsets {
    didSet {
        updateConstraintsForPlaceholderLabel()
    }
}

override public init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    commonInit()
}

required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
}

private func commonInit() {
    NotificationCenter.default.addObserver(self,
                                                     selector: #selector(textDidChange),
                                                     name: NSNotification.Name.UITextViewTextDidChange,
                                                     object: nil)

    placeholderLabel.font = font
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
    placeholderLabel.text = placeholder
    placeholderLabel.numberOfLines = 0
    placeholderLabel.backgroundColor = UIColor.clear
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(placeholderLabel)
    updateConstraintsForPlaceholderLabel()
}

private func updateConstraintsForPlaceholderLabel() {
    var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
        options: [],
        metrics: nil,
        views: ["placeholder": placeholderLabel])
    newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|-(\(textContainerInset.top))-[placeholder]",
        options: [],
        metrics: nil,
        views: ["placeholder": placeholderLabel])
    newConstraints.append(NSLayoutConstraint(
        item: placeholderLabel,
        attribute: .width,
        relatedBy: .equal,
        toItem: self,
        attribute: .width,
        multiplier: 1.0,
        constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
    ))
    removeConstraints(placeholderLabelConstraints)
    addConstraints(newConstraints)
    placeholderLabelConstraints = newConstraints
}

@objc private func textDidChange() {
    placeholderLabel.isHidden = !text.isEmpty
}

public override func layoutSubviews() {
    super.layoutSubviews()
    placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}

deinit {
    NotificationCenter.default.removeObserver(self,
                                                        name: NSNotification.Name.UITextViewTextDidChange,
                                                        object: nil)
}

}

나는 수업을 재빠르게 썼다.필요할 때마다 이 클래스를 가져와야 합니다.

평판 때문에 코멘트를 추가할 수 없습니다.@clearlight answer에 딜러 니즈를 1개 추가합니다.

func textViewDidBeginEditing(_ textView: UITextView) { 
        cell.placeholderLabel.isHidden = !textView.text.isEmpty
}

필요.

textViewDidChange first (처음이라고 불리지 않음)

텍스트 보기에 사용할 수 있는 자리 표시자가 없습니다.사용자가 텍스트 뷰에 입력할 때 라벨을 붙인 다음 사용자가 입력할 때 라벨을 숨기거나 기본값으로 설정해야 합니다. 모든 값을 제거합니다.

언급URL : https://stackoverflow.com/questions/27652227/add-placeholder-text-inside-uitextview-in-swift

반응형