Placeholder in UITextView

前端 未结 30 3085
野趣味
野趣味 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:10

    I wasn't too happy with any of the solutions posted as they were a bit heavy. Adding views to the view isn't really ideal (especially in drawRect:). They both had leaks, which isn't acceptable either.

    Here is my solution: SAMTextView

    SAMTextView.h

    //
    //  SAMTextView.h
    //  SAMTextView
    //
    //  Created by Sam Soffes on 8/18/10.
    //  Copyright 2010-2013 Sam Soffes. All rights reserved.
    //
    
    #import 
    
    /**
     UITextView subclass that adds placeholder support like UITextField has.
     */
    @interface SAMTextView : UITextView
    
    /**
     The string that is displayed when there is no other text in the text view.
    
     The default value is `nil`.
     */
    @property (nonatomic, strong) NSString *placeholder;
    
    /**
     The color of the placeholder.
    
     The default is `[UIColor lightGrayColor]`.
     */
    @property (nonatomic, strong) UIColor *placeholderTextColor;
    
    /**
     Returns the drawing rectangle for the text views’s placeholder text.
    
     @param bounds The bounding rectangle of the receiver.
     @return The computed drawing rectangle for the placeholder text.
     */
    - (CGRect)placeholderRectForBounds:(CGRect)bounds;
    
    @end
    

    SAMTextView.m

    //
    //  SAMTextView.m
    //  SAMTextView
    //
    //  Created by Sam Soffes on 8/18/10.
    //  Copyright 2010-2013 Sam Soffes. All rights reserved.
    //
    
    #import "SAMTextView.h"
    
    @implementation SAMTextView
    
    #pragma mark - Accessors
    
    @synthesize placeholder = _placeholder;
    @synthesize placeholderTextColor = _placeholderTextColor;
    
    - (void)setText:(NSString *)string {
      [super setText:string];
      [self setNeedsDisplay];
    }
    
    
    - (void)insertText:(NSString *)string {
      [super insertText:string];
      [self setNeedsDisplay];
    }
    
    
    - (void)setAttributedText:(NSAttributedString *)attributedText {
      [super setAttributedText:attributedText];
      [self setNeedsDisplay];
    }
    
    
    - (void)setPlaceholder:(NSString *)string {
      if ([string isEqual:_placeholder]) {
        return;
      }
    
      _placeholder = string;
      [self setNeedsDisplay];
    }
    
    
    - (void)setContentInset:(UIEdgeInsets)contentInset {
      [super setContentInset:contentInset];
      [self setNeedsDisplay];
    }
    
    
    - (void)setFont:(UIFont *)font {
      [super setFont:font];
      [self setNeedsDisplay];
    }
    
    
    - (void)setTextAlignment:(NSTextAlignment)textAlignment {
      [super setTextAlignment:textAlignment];
      [self setNeedsDisplay];
    }
    
    
    #pragma mark - NSObject
    
    - (void)dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
    }
    
    
    #pragma mark - UIView
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
      if ((self = [super initWithCoder:aDecoder])) {
        [self initialize];
      }
      return self;
    }
    
    
    - (id)initWithFrame:(CGRect)frame {
      if ((self = [super initWithFrame:frame])) {
        [self initialize];
      }
      return self;
    }
    
    
    - (void)drawRect:(CGRect)rect {
      [super drawRect:rect];
    
      if (self.text.length == 0 && self.placeholder) {
        rect = [self placeholderRectForBounds:self.bounds];
    
        UIFont *font = self.font ? self.font : self.typingAttributes[NSFontAttributeName];
    
        // Draw the text
        [self.placeholderTextColor set];
        [self.placeholder drawInRect:rect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:self.textAlignment];
      }
    }
    
    
    #pragma mark - Placeholder
    
    - (CGRect)placeholderRectForBounds:(CGRect)bounds {
      // Inset the rect
      CGRect rect = UIEdgeInsetsInsetRect(bounds, self.contentInset);
    
      if (self.typingAttributes) {
        NSParagraphStyle *style = self.typingAttributes[NSParagraphStyleAttributeName];
        if (style) {
          rect.origin.x += style.headIndent;
          rect.origin.y += style.firstLineHeadIndent;
        }
      }
    
      return rect;
    }
    
    
    #pragma mark - Private
    
    - (void)initialize {
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:self];
    
      self.placeholderTextColor = [UIColor colorWithWhite:0.702f alpha:1.0f];
    }
    
    
    - (void)textChanged:(NSNotification *)notification {
      [self setNeedsDisplay];
    }
    
    @end
    

    It's a lot simpler than the others, as it doesn't use subviews (or have leaks). Feel free to use it.

    Update 11/10/11: It is now documented and supports use in Interface Builder.

    Update 11/24/13: Point to new repo.

提交回复
热议问题