我的应用程序使用UITextView。现在我想让UITextView有一个占位符,类似于你可以为UITextField设置的占位符。

如何做到这一点?


当前回答

首先在.h文件中取一个标签。

这里我取

UILabel * lbl;

然后在。m中viewDidLoad下声明它

lbl = [[UILabel alloc] initWithFrame:CGRectMake(8.0, 0.0,250, 34.0)];

lbl.font=[UIFont systemFontOfSize:14.0];

[lbl setText:@"Write a message..."];

[lbl setBackgroundColor:[UIColor clearColor]];

[lbl setTextColor:[UIColor lightGrayColor]];

[textview addSubview:lbl];

textview是我的textview。

现在声明

-(void)textViewDidChange:(UITextView *)textView {

 if (![textView hasText]){

    lbl.hidden = NO;

 }
 else{
    lbl.hidden = YES;
 }

}

和你的Textview占位符准备好了!

其他回答

让我们简单点

创建一个UILabel并把它放在你的文本视图上(给文本作为占位符-设置颜色为灰色-你可以在你的xib中做这一切) 现在在头文件中声明UILabel和textviewDelegate 现在你可以简单地隐藏标签,当你点击textview

完整代码如下

@interface ViewController :UIViewController<UITextViewDelegate>{
 }
   @property (nonatomic,strong) IBOutlet UILabel *PlceHolder_label;
   @property (nonatomic,strong) IBOutlet UITextView *TextView;

@end

实现

@implementation UploadFoodImageViewController
@synthesize PlceHolder_label,TextView;

  - (void)viewDidLoad
    {
       [super viewDidLoad];
    }


 - (BOOL)textViewShouldBeginEditing:(UITextView *)textView{

       if([textView isEqual:TextView]){
            [PlceHolder_label setHidden:YES];
            [self.tabScrlVw setContentOffset:CGPointMake(0,150) animated:YES];
          }
      return YES;
    }

@end

别忘了连接textView和UILabel文件所有者从xib

    - (void)textViewDidChange:(UITextView *)textView
{
    placeholderLabel.hidden = YES;
}

在textview上放一个标签。

Jason的答案在iOS7中看起来有点不对劲,通过调整_placeHolderLabel的偏移量来修复它:

- (void)drawRect:(CGRect)rect
{
    if( [[self placeholder] length] > 0 )
    {
        if (_placeHolderLabel == nil )
        {
            if ([[UIDevice currentDevice].systemVersion floatValue] >= 7)
                _placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(4,8,self.bounds.size.width - 8,0)];
            else
                _placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
            _placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
            _placeHolderLabel.numberOfLines = 0;
            _placeHolderLabel.font = self.font;
            _placeHolderLabel.backgroundColor = [UIColor clearColor];
            _placeHolderLabel.textColor = self.placeholderColor;
            _placeHolderLabel.alpha = 0;
            _placeHolderLabel.tag = 999;
            [self addSubview:_placeHolderLabel];
        }

        _placeHolderLabel.text = self.placeholder;
        [_placeHolderLabel sizeToFit];
        [self sendSubviewToBack:_placeHolderLabel];
    }

    if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
    {
        [[self viewWithTag:999] setAlpha:1];
    }

    [super drawRect:rect];
}

模拟本机占位符


一个常见的抱怨是iOS没有为文本视图提供原生占位符功能。下面的UITextView扩展试图通过提供人们期望从本机特性获得的便利来解决这个问题,只需要一行代码就可以向textview实例添加占位符。

这个解决方案的缺点是,因为它菊花链委托调用,它很容易(不太可能)在iOS更新中更改UITextViewDelegate协议。具体来说,如果iOS添加了新的协议方法,并且你在带有占位符的文本视图的委托中实现了它们中的任何一个,这些方法将不会被调用,除非你也更新了扩展来转发这些调用。

或者,内联占位符的答案是一个坚如磐石的和简单的可以。


使用例子:


•如果获得占位符的文本视图没有使用UITextViewDelegate:

    /* Swift 3 */

    class NoteViewController : UIViewController {
        @IBOutlet weak var noteView: UITextView!
        override func viewDidLoad() {
            noteView.addPlaceholder("Enter some text...",  color: UIColor.lightGray)
        }
    }

                                            -- 或者——

•如果获得占位符的文本视图使用了UITextViewDelegate:

    /* Swift 3 */

    class NoteViewController : UIViewController, UITextViewDelegate {
        @IBOutlet weak var noteView: UITextView!
        override func viewDidLoad() {
            noteView.addPlaceholder("Phone #", color: UIColor.lightGray, delegate: self)
        }
    }

实现(UITextView扩展):


/* Swift 3 */

extension UITextView: UITextViewDelegate
{

    func addPlaceholder(_ placeholderText : String, 
                      color : UIColor? = UIColor.lightGray,
                      delegate : UITextViewDelegate? = nil) {

        self.delegate = self             // Make receiving textview instance a delegate
        let placeholder = UITextView()   // Need delegate storage ULabel doesn't provide
        placeholder.isUserInteractionEnabled = false  //... so we *simulate* UILabel
        self.addSubview(placeholder)     // Add to text view instance's view tree               
        placeholder.sizeToFit()          // Constrain to fit inside parent text view
        placeholder.tintColor = UIColor.clear // Unused in textviews. Can host our 'tag'
        placeholder.frame.origin = CGPoint(x: 5, y: 0) // Don't cover I-beam cursor
        placeholder.delegate = delegate  // Use as cache for caller's delegate 
        placeholder.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
        placeholder.text = placeholderText
        placeholder.textColor = color
    }

      
    func findPlaceholder() -> UITextView? { // find placeholder by its tag 
        for subview in self.subviews {
            if let textview = subview as? UITextView {
                if textview.tintColor == UIColor.clear { // sneaky tagging scheme
                    return textview
                }
            }
        }
        return nil
    }
     
    /* 
     * Safely daisychain to caller delegate methods as appropriate...
     */

    public func textViewDidChange(_ textView: UITextView) { // ←  need this delegate method
        if let placeholder = findPlaceholder() {
            placeholder.isHidden = !self.text.isEmpty // ← ... to do this
            placeholder.delegate?.textViewDidChange?(textView)
        } 
    }

    /* 
     * Since we're becoming a delegate on behalf of this placeholder-enabled
     * text view instance, we must forward *all* that protocol's activity expected
     * by the instance, not just the particular optional protocol method we need to
     * intercept, above.
     */

    public func textViewDidEndEditing(_ textView: UITextView) {
        if let placeholder = findPlaceholder() {
            placeholder.delegate?.textViewDidEndEditing?(textView)
        } 
    }

    public func textViewDidBeginEditing(_ textView: UITextView) {
        if let placeholder = findPlaceholder() {
            placeholder.delegate?.textViewDidBeginEditing?(textView)
        } 
    }

    public  func textViewDidChangeSelection(_ textView: UITextView) {
        if let placeholder = findPlaceholder() {
            placeholder.delegate?.textViewDidChangeSelection?(textView)
        } 
    }

    public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
        if let placeholder = findPlaceholder() {
            guard let retval = placeholder.delegate?.textViewShouldEndEditing?(textView) else {
                return true
            }
            return retval
        }
        return true
    }

    public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
        if let placeholder = findPlaceholder() {
            guard let retval = placeholder.delegate?.textViewShouldBeginEditing?(textView) else {
                return true
            }
            return retval
        } 
        return true
    }

    public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if let placeholder = findPlaceholder() {
            guard let retval = placeholder.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) else {
                return true
            }
            return retval
        } 
        return true
    }

    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        if let placeholder = findPlaceholder() {
                guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction:
                    interaction) else {
                        return true
            }
            return retval
        }
        return true
    }

    public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        if let placeholder = findPlaceholder() {
            guard let retval = placeholder.delegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) else {
                return true
            }
            return retval
        }
        return true
    }
}

1. 作为一个像UITextView这样的基本iOS类的扩展,重要的是要知道这段代码没有与任何不激活占位符的textview交互,例如textview实例没有被调用addPlaceholder()初始化

2. 支持占位符的文本视图透明地变成一个UITextViewDelegate来跟踪字符计数,以控制占位符可见性。如果一个委托被传递给addPlaceholder(),这段代码会将委托回调给该委托。

3.作者正在研究如何检查UITextViewDelegate协议并自动代理它,而不必硬编码每个方法。这将使代码免受方法签名更改和添加到协议中的新方法的影响。

如果有人需要Swift的解决方案:

添加UITextViewDelegate到类中

var placeHolderText = "Placeholder Text..."

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

func textViewShouldBeginEditing(textView: UITextView) -> Bool {

    self.textView.textColor = .black

    if(self.textView.text == placeHolderText) {
        self.textView.text = ""
    }

    return true
}

func textViewDidEndEditing(textView: UITextView) {
    if(textView.text == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    }
}

override func viewWillAppear(animated: Bool) {

    if(currentQuestion.answerDisplayValue == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    } else {
        self.textView.text = "xxx" // load default text / or stored 
        self.textView.textColor = .black
    }
}