Placeholder in UITextView

前端 未结 30 2821
野趣味
野趣味 2020-11-22 16:01

My application uses an UITextView. Now I want the UITextView to have a placeholder similar to the one you can set for an UITextField.<

30条回答
  •  隐瞒了意图╮
    2020-11-22 16:26

    Below is a Swift port of "SAMTextView" ObjC code posted as one of the first handful of replies to the question. I tested it on iOS 8. I tweaked a couple of things, including the bounds offset for the placement of the placeholder text, as the original was too high and too far right (used suggestion in one of the comments to that post).

    I know there are a lot of simple solutions, but I like the approach of subclassing UITextView because it's reusable and I don't have to clutter classes utilizing it with the mechanisms.

    Swift 2.2:

    import UIKit
    
    class PlaceholderTextView: UITextView {
    
        @IBInspectable var placeholderColor: UIColor = UIColor.lightGrayColor()
        @IBInspectable var placeholderText: String = ""
    
        override var font: UIFont? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var contentInset: UIEdgeInsets {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var textAlignment: NSTextAlignment {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var text: String? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var attributedText: NSAttributedString? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setUp()
        }
    
        override init(frame: CGRect, textContainer: NSTextContainer?) {
            super.init(frame: frame, textContainer: textContainer)
        }
    
        private func setUp() {
            NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PlaceholderTextView.textChanged(_:)),
                                                             name: UITextViewTextDidChangeNotification, object: self)
        }
    
        func textChanged(notification: NSNotification) {
            setNeedsDisplay()
        }
    
        func placeholderRectForBounds(bounds: CGRect) -> CGRect {
            var x = contentInset.left + 4.0
            var y = contentInset.top  + 9.0
            let w = frame.size.width - contentInset.left - contentInset.right - 16.0
            let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0
    
            if let style = self.typingAttributes[NSParagraphStyleAttributeName] as? NSParagraphStyle {
                x += style.headIndent
                y += style.firstLineHeadIndent
            }
            return CGRect(x: x, y: y, width: w, height: h)
        }
    
        override func drawRect(rect: CGRect) {
            if text!.isEmpty && !placeholderText.isEmpty {
                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.alignment = textAlignment
                let attributes: [ String: AnyObject ] = [
                    NSFontAttributeName : font!,
                    NSForegroundColorAttributeName : placeholderColor,
                    NSParagraphStyleAttributeName  : paragraphStyle]
    
                placeholderText.drawInRect(placeholderRectForBounds(bounds), withAttributes: attributes)
            }
            super.drawRect(rect)
        }
    }
    

    Swift 4.2:

    import UIKit
    
    class PlaceholderTextView: UITextView {
    
        @IBInspectable var placeholderColor: UIColor = UIColor.lightGray
        @IBInspectable var placeholderText: String = ""
    
        override var font: UIFont? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var contentInset: UIEdgeInsets {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var textAlignment: NSTextAlignment {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var text: String? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override var attributedText: NSAttributedString? {
            didSet {
                setNeedsDisplay()
            }
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setUp()
        }
    
        override init(frame: CGRect, textContainer: NSTextContainer?) {
            super.init(frame: frame, textContainer: textContainer)
        }
    
        private func setUp() {
            NotificationCenter.default.addObserver(self,
             selector: #selector(self.textChanged(notification:)),
             name: Notification.Name("UITextViewTextDidChangeNotification"),
             object: nil)
        }
    
        @objc func textChanged(notification: NSNotification) {
            setNeedsDisplay()
        }
    
        func placeholderRectForBounds(bounds: CGRect) -> CGRect {
            var x = contentInset.left + 4.0
            var y = contentInset.top  + 9.0
            let w = frame.size.width - contentInset.left - contentInset.right - 16.0
            let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0
    
            if let style = self.typingAttributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle {
                x += style.headIndent
                y += style.firstLineHeadIndent
            }
            return CGRect(x: x, y: y, width: w, height: h)
        }
    
        override func draw(_ rect: CGRect) {
            if text!.isEmpty && !placeholderText.isEmpty {
                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.alignment = textAlignment
                let attributes: [NSAttributedString.Key: Any] = [
                NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue) : font!,
                NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue) : placeholderColor,
                NSAttributedString.Key(rawValue: NSAttributedString.Key.paragraphStyle.rawValue)  : paragraphStyle]
    
                placeholderText.draw(in: placeholderRectForBounds(bounds: bounds), withAttributes: attributes)
            }
            super.draw(rect)
        }
    }
    

提交回复
热议问题