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

如何做到这一点?


当前回答

让我们简单点

创建一个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

其他回答

这个帖子已经有了很多答案,但这里是我更喜欢的版本。

它扩展了现有的UITextView类,因此很容易重用,并且它不拦截像textViewDidChange这样的事件(这可能会破坏用户的代码,如果他们已经在其他地方拦截了这些事件)。

使用我的代码(如下所示),你可以很容易地添加一个占位符到任何你的UITextViews像这样:

self.textViewComments.placeholder = @"(Enter some comments here.)";

当你设置这个新的占位符值时,它会悄悄地在你的UITextView上添加一个UILabel,然后在必要时隐藏/显示它:

好的,要做这些改变,添加一个包含以下代码的"UITextViewHelper.h"文件:

//  UITextViewHelper.h
//  Created by Michael Gledhill on 13/02/15.

#import <Foundation/Foundation.h>

@interface UITextView (UITextViewHelper)

@property (nonatomic, strong) NSString* placeholder;
@property (nonatomic, strong) UILabel* placeholderLabel;
@property (nonatomic, strong) NSString* textValue;

-(void)checkIfNeedToDisplayPlaceholder;

@end

…和一个UITextViewHelper。M文件包含:

//  UITextViewHelper.m
//  Created by Michael Gledhill on 13/02/15.
//
//  This UITextView category allows us to easily display a PlaceHolder string in our UITextView.
//  The downside is that, your code needs to set the "textValue" rather than the "text" value to safely set the UITextView's text.
//
#import "UITextViewHelper.h"
#import <objc/runtime.h>

@implementation UITextView (UITextViewHelper)

#define UI_PLACEHOLDER_TEXT_COLOR [UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0]

@dynamic placeholder;
@dynamic placeholderLabel;
@dynamic textValue;

-(void)setTextValue:(NSString *)textValue
{
    //  Change the text of our UITextView, and check whether we need to display the placeholder.
    self.text = textValue;
    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)textValue
{
    return self.text;
}

-(void)checkIfNeedToDisplayPlaceholder
{
    //  If our UITextView is empty, display our Placeholder label (if we have one)
    if (self.placeholderLabel == nil)
        return;

    self.placeholderLabel.hidden = (![self.text isEqualToString:@""]);
}

-(void)onTap
{
    //  When the user taps in our UITextView, we'll see if we need to remove the placeholder text.
    [self checkIfNeedToDisplayPlaceholder];

    //  Make the onscreen keyboard appear.
    [self becomeFirstResponder];
}

-(void)keyPressed:(NSNotification*)notification
{
    //  The user has just typed a character in our UITextView (or pressed the delete key).
    //  Do we need to display our Placeholder label ?
   [self checkIfNeedToDisplayPlaceholder];
}

#pragma mark - Add a "placeHolder" string to the UITextView class

NSString const *kKeyPlaceHolder = @"kKeyPlaceHolder";
-(void)setPlaceholder:(NSString *)_placeholder
{
    //  Sets our "placeholder" text string, creates a new UILabel to contain it, and modifies our UITextView to cope with
    //  showing/hiding the UILabel when needed.
    objc_setAssociatedObject(self, &kKeyPlaceHolder, (id)_placeholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    self.placeholderLabel = [[UILabel alloc] initWithFrame:self.frame];
    self.placeholderLabel.numberOfLines = 1;
    self.placeholderLabel.text = _placeholder;
    self.placeholderLabel.textColor = UI_PLACEHOLDER_TEXT_COLOR;
    self.placeholderLabel.backgroundColor = [UIColor clearColor];
    self.placeholderLabel.userInteractionEnabled = true;
    self.placeholderLabel.font = self.font;
    [self addSubview:self.placeholderLabel];

    [self.placeholderLabel sizeToFit];

    //  Whenever the user taps within the UITextView, we'll give the textview the focus, and hide the placeholder if necessary.
    [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)]];

    //  Whenever the user types something in the UITextView, we'll see if we need to hide/show the placeholder label.
    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)placeholder
{
    //  Returns our "placeholder" text string
    return objc_getAssociatedObject(self, &kKeyPlaceHolder);
}

#pragma mark - Add a "UILabel" to this UITextView class

NSString const *kKeyLabel = @"kKeyLabel";
-(void)setPlaceholderLabel:(UILabel *)placeholderLabel
{
    //  Stores our new UILabel (which contains our placeholder string)
    objc_setAssociatedObject(self, &kKeyLabel, (id)placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(UILabel*)placeholderLabel
{
    //  Returns our new UILabel
    return objc_getAssociatedObject(self, &kKeyLabel);
}
@end

是的,它有很多代码,但是一旦你把它添加到你的项目中,并包含了.h文件……

#import "UITextViewHelper.h"

...你可以很容易地在UITextViews中使用占位符。

不过有一个问题。

如果你这样做:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.text = @"Ooooh, hello there";

...占位符将出现在文本的顶部。设置文本值时,不会调用任何常规通知,因此我不知道如何调用我的函数来决定是否显示/隐藏占位符。

解决方案是设置textValue而不是text:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.textValue = @"Ooooh, hello there";

或者,您可以设置文本值,然后调用checkIfNeedToDisplayPlaceholder。

self.textViewComments.text = @"Ooooh, hello there";
[self.textViewComments checkIfNeedToDisplayPlaceholder];

我喜欢这样的解决方案,因为它们“填补了”苹果提供给我们的东西和我们(作为开发者)在应用程序中实际需要的东西之间的空白。只需编写一次此代码,将其添加到“helper”.m/.h文件库中,随着时间的推移,SDK实际上开始变得不那么令人沮丧。

(我写了一个类似的帮助添加一个“清除”按钮到我的UITextViews,另一个烦人的东西存在于UITextField但不在UITextView…)

这里有一个更简单的解决方案,它的行为完全像UITextField的占位符,但不需要绘制自定义视图,或辞职第一响应器。

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

    if (textView.text.length == 0){
        textView.textColor = [UIColor lightGrayColor];
        textView.text = placeholderText;
        [textView setSelectedRange:NSMakeRange(0, 0)];
        isPlaceholder = YES;

    } else if (isPlaceholder && ![textView.text isEqualToString:placeholderText]) {
        textView.text = [textView.text substringToIndex:1];
        textView.textColor = [UIColor blackColor];
        isPlaceholder = NO;
    }

}

(else if语句中的第二个检查是针对没有输入任何内容且用户按下退格键的情况)

只需要将你的类设置为UITextViewDelegate。在viewDidLoad中,你应该这样初始化

- (void) viewDidLoad{
    // initialize placeholder text
    placeholderText = @"some placeholder";
    isPlaceholder = YES;
    self.someTextView.text = placeholderText;
    self.someTextView.textColor = [UIColor lightGrayColor];
    [self.someTextView setSelectedRange:NSMakeRange(0, 0)];

    // assign UITextViewDelegate
    self.someTextView.delegate = self;
}
    - (void)textViewDidChange:(UITextView *)textView
{
    placeholderLabel.hidden = YES;
}

在textview上放一个标签。

我遵循了这个链接的代码。只有7个简单的步骤。它添加了一个UILabel的textView和隐藏/显示标签时,文本输入或从textView通过textView的textViewDidChangeSelection(_ textView: UITextView)委托方法。我将步骤放在代码上方的注释中。

// 1. make sure to include the UITextViewDelegate
class YourClass: UITextViewDelegate {

    @IBOutlet weak var textView : UITextView!

    // 2. create placeholder textLabel
    let placeHolderTextLabel: UILabel = {
        let placeholderLabel = UILabel()
        placeholderLabel.text = "Placeholder text..."
        placeholderLabel.sizeToFit()
        placeholderLabel.textColor = UIColor.lightGray
        return placeholderLabel
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 3. set textView delegate
        textView.delegate = self

        configurePlaceholderTextLabel()
    }


    func configurePlaceholderTextLabel() {

        // 4. add placeholder label to textView, set it's frame and font
        textView.addSubview(placeHolderTextLabel)
        placeHolderTextLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
        placeHolderTextLabel.font = UIFont.systemFont(ofSize: (textView.font?.pointSize)!)

        // 5. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView
        placeHolderTextLabel.isHidden = !textView.text.isEmpty

    }

    // 6. implement textView delegate method to update the placeHolderTextLabel when the text is changed
    func textViewDidChangeSelection(_ textView: UITextView) {

        // 7. decide wether the placeHolderTextLabel is hidden or not depending on if there is or isn't text inside the textView when text in textView is changed
        placeHolderTextLabel.isHidden = !textView.text.isEmpty
    }

}

我用swift写了一个类。您可以在需要时导入这个类。

import UIKit

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)
}

}