解决UITextView的placeholder属性
2013-12-17 14:41
465 查看
解决UITextView的placeholder属性,并解决了键盘遮挡问题,代码如下:
第一个类:
#import <UIKit/UIKit.h>
@interface HPTextViewInternal
: UITextView {
NSString *placeholder;
UIColor *placeholderColor;
@private
UILabel *placeHolderLabel;
}
@property(nonatomic, retain) UILabel *placeHolderLabel;
@property(nonatomic, retain) NSString *placeholder;
@property(nonatomic, retain) UIColor *placeholderColor;
-(void)textChanged:(NSNotification*)notification;
@end
#import "HPTextViewInternal.h"
@implementation HPTextViewInternal
@synthesize placeHolderLabel;
@synthesize placeholder;
@synthesize placeholderColor;
- (void)dealloc
{
[[NSNotificationCenterdefaultCenter] removeObserver:self];
[placeHolderLabelrelease]; placeHolderLabel = nil;
[placeholderColorrelease]; placeholderColor = nil;
[placeholderrelease]; placeholder = nil;
[superdealloc];
}
- (void)awakeFromNib
{
[superawakeFromNib];
[selfsetPlaceholder:@""];
[selfsetPlaceholderColor:[UIColorlightGrayColor]];
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(textChanged:) name:UITextViewTextDidChangeNotificationobject:nil];
}
- (id)initWithFrame:(CGRect)frame
{
if(
(self =
[superinitWithFrame:frame])
)
{
[selfsetPlaceholder:@""];
[selfsetPlaceholderColor:[UIColorlightGrayColor]];
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(textChanged:) name:UITextViewTextDidChangeNotificationobject:nil];
}
returnself;
}
- (void)textChanged:(NSNotification *)notification
{
if([[selfplaceholder] length]
== 0)
{
return;
}
if([[selftext] length]
== 0)
{
[[selfviewWithTag:999] setAlpha:1];
}
else
{
[[selfviewWithTag:999] setAlpha:0];
}
}
- (void)drawRect:(CGRect)rect
{
if(
[[selfplaceholder] length]
> 0 )
{
if ( placeHolderLabel == nil )
{
placeHolderLabel =
[[UILabelalloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
placeHolderLabel.lineBreakMode = UILineBreakModeWordWrap;
placeHolderLabel.numberOfLines = 0;
placeHolderLabel.font = self.font;
placeHolderLabel.backgroundColor =
[UIColorclearColor];
placeHolderLabel.textColor = self.placeholderColor;
placeHolderLabel.alpha = 0;
placeHolderLabel.tag = 999;
[selfaddSubview:placeHolderLabel];
}
placeHolderLabel.text = self.placeholder;
[placeHolderLabelsizeToFit];
[selfsendSubviewToBack:placeHolderLabel];
}
if(
[[selftext] length]
== 0 &&
[[selfplaceholder] length]
> 0 )
{
[[selfviewWithTag:999] setAlpha:1];
}
[superdrawRect:rect];
}
-(void)setText:(NSString *)text
{
[supersetText:text];
[selftextChanged:nil];
BOOL originalValue
= self.scrollEnabled;
//If
one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO,
//setting
the text programatically will cause UIKit to search upwards until it finds a scrollView with scrollEnabled==yes
//then
scroll it erratically. Setting scrollEnabled temporarily to YES prevents this.
[selfsetScrollEnabled:YES];
[supersetText:text];
[selfsetScrollEnabled:originalValue];
}
-(void)setContentOffset:(CGPoint)s
{
if(self.tracking || self.decelerating){
//initiated by user...
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 0;
insets.top = 0;
self.contentInset =
insets;
} else {
float bottomOffset
= (self.contentSize.height - self.frame.size.height + self.contentInset.bottom);
if(s.y <
bottomOffset && self.scrollEnabled){
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 8;
insets.top = 0;
self.contentInset =
insets;
}
}
[supersetContentOffset:s];
}
-(void)setContentInset:(UIEdgeInsets)s
{
UIEdgeInsets insets
= s;
if(s.bottom>8)
insets.bottom = 0;
insets.top = 0;
[supersetContentInset:insets];
}
-(void)setContentSize:(CGSize)contentSize
{
//
is this an iOS5 bug? Need testing!
if(self.contentSize.height >
contentSize.height)
{
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 0;
insets.top = 0;
self.contentInset =
insets;
}
[supersetContentSize:contentSize];
}
@end
第二个类:
#import <UIKit/UIKit.h>
@classHPGrowingTextView;
@classHPTextViewInternal;
@protocol HPGrowingTextViewDelegate
@optional
- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView
shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView;
- (void)growingTextView:(HPGrowingTextView *)growingTextView
willChangeHeight:(float)height;
- (void)growingTextView:(HPGrowingTextView *)growingTextView
didChangeHeight:(float)height;
- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView;
@end
@interface HPGrowingTextView : UIView <UITextViewDelegate>
{
HPTextViewInternal *internalTextView;
int minHeight;
int maxHeight;
//class properties
int maxNumberOfLines;
int minNumberOfLines;
BOOL animateHeightChange;
//uitextview properties
NSObject <HPGrowingTextViewDelegate>
*__unsafe_unretained delegate;
UITextAlignment textAlignment;
NSRange selectedRange;
BOOL editable;
UIDataDetectorTypes dataDetectorTypes;
UIReturnKeyType returnKeyType;
UIEdgeInsets contentInset;
}
//real class properties
@propertyint maxNumberOfLines;
@propertyint minNumberOfLines;
@propertyBOOL animateHeightChange;
@property (nonatomic, strong) UITextView *internalTextView;
//uitextview properties
@property(unsafe_unretained) NSObject<HPGrowingTextViewDelegate>
*delegate;
@property(nonatomic,strong) NSString *text;
@property(nonatomic,strong) UIFont *font;
@property(nonatomic,strong) UIColor *textColor;
@property(nonatomic) UITextAlignment textAlignment;
// default is UITextAlignmentLeft
@property(nonatomic) NSRange selectedRange;
// only ranges of length 0 are supported
@property(nonatomic,getter=isEditable) BOOL editable;
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA,
__IPHONE_3_0);
@property (nonatomic) UIReturnKeyType returnKeyType;
@property (assign) UIEdgeInsets contentInset;
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
//uitextview methods
//need others? use .internalTextView
- (BOOL)becomeFirstResponder;
- (BOOL)resignFirstResponder;
- (BOOL)isFirstResponder;
- (BOOL)hasText;
- (void)scrollRangeToVisible:(NSRange)range;
//设置Placeholder属性
-(void)settingPlaceholder:(NSString *)string;
@end
#import "HPGrowingTextView.h"
#import "HPTextViewInternal.h"
@interface HPGrowingTextView(private)
-(void)commonInitialiser;
-(void)resizeTextView:(NSInteger)newSizeH;
-(void)growDidStop;
@end
@implementation HPGrowingTextView
@synthesize internalTextView;
@synthesize delegate;
@synthesize font;
@synthesize textColor;
@synthesize textAlignment;
@synthesize selectedRange;
@synthesize editable;
@synthesize dataDetectorTypes;
@synthesize animateHeightChange;
@synthesize returnKeyType;
// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [superinitWithCoder:aDecoder]))
{
[selfcommonInitialiser];
}
returnself;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [superinitWithFrame:frame]))
{
[selfcommonInitialiser];
}
returnself;
}
-(void)commonInitialiser
{
// Initialization code
CGRect r = self.frame;
r.origin.y = 0;
r.origin.x = 0;
internalTextView = [[HPTextViewInternalalloc] initWithFrame:r];
internalTextView.delegate = self;
internalTextView.scrollEnabled = NO;
internalTextView.font =
[UIFontfontWithName:@"Helvetica"size:13];
internalTextView.contentInset = UIEdgeInsetsZero;
internalTextView.showsHorizontalScrollIndicator = NO;
internalTextView.text = @"-";
[selfaddSubview:internalTextView];
minHeight = internalTextView.frame.size.height;
minNumberOfLines = 1;
animateHeightChange = YES;
internalTextView.text = @"";
//设置Placeholder属性
[selfsetMaxNumberOfLines:3];
}
-(void)settingPlaceholder:(NSString *)string
{
internalTextView.placeholder =
string;
}
-(CGSize)sizeThatFits:(CGSize)size
{
if (self.text.length == 0)
{
size.height = minHeight;
}
return size;
}
-(void)layoutSubviews
{
[superlayoutSubviews];
CGRect r = self.bounds;
r.origin.y = 0;
r.origin.x = contentInset.left;
r.size.width -= contentInset.left + contentInset.right;
internalTextView.frame =
r;
}
-(void)setContentInset:(UIEdgeInsets)inset
{
contentInset = inset;
CGRect r = self.frame;
r.origin.y = inset.top -
inset.bottom;
r.origin.x = inset.left;
r.size.width -=
inset.left + inset.right;
internalTextView.frame =
r;
[selfsetMaxNumberOfLines:maxNumberOfLines];
[selfsetMinNumberOfLines:minNumberOfLines];
}
-(UIEdgeInsets)contentInset
{
returncontentInset;
}
-(void)setMaxNumberOfLines:(int)n
{
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
NSString *saveText = internalTextView.text,
*newText = @"-";
internalTextView.delegate = nil;
internalTextView.hidden = YES;
for (int i = 1;
i < n; ++i)
newText = [newText stringByAppendingString:@"\n|W|"];
internalTextView.text =
newText;
maxHeight = internalTextView.contentSize.height;
internalTextView.text =
saveText;
internalTextView.hidden = NO;
internalTextView.delegate = self;
[selfsizeToFit];
maxNumberOfLines = n;
}
-(int)maxNumberOfLines
{
returnmaxNumberOfLines;
}
-(void)setMinNumberOfLines:(int)m
{
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
NSString *saveText = internalTextView.text,
*newText = @"-";
internalTextView.delegate = nil;
internalTextView.hidden = YES;
for (int i = 1;
i < m; ++i)
newText = [newText stringByAppendingString:@"\n|W|"];
internalTextView.text =
newText;
minHeight = internalTextView.contentSize.height;
internalTextView.text =
saveText;
internalTextView.hidden = NO;
internalTextView.delegate = self;
[selfsizeToFit];
minNumberOfLines = m;
}
-(int)minNumberOfLines
{
returnminNumberOfLines;
}
- (void)textViewDidChange:(UITextView *)textView
{
//size of content, so we can set the frame of self
NSInteger newSizeH = internalTextView.contentSize.height;
if(newSizeH < minHeight ||
!internalTextView.hasText) newSizeH = minHeight; //not
smalles than minHeight
if (internalTextView.frame.size.height > maxHeight)
newSizeH = maxHeight; // not taller than maxHeight
if (internalTextView.frame.size.height !=
newSizeH)
{
// [fixed] Pasting too much text into the view failed to fire the height change,
// thanks to Gwynne
<http://blog.darkrainfall.org/>
if (newSizeH
> maxHeight && internalTextView.frame.size.height <= maxHeight)
{
newSizeH = maxHeight;
}
if (newSizeH <= maxHeight)
{
if(animateHeightChange)
{
if ([UIViewresolveClassMethod:@selector(animateWithDuration:animations:)])
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
[UIViewanimateWithDuration:0.1f
delay:0
options:(UIViewAnimationOptionAllowUserInteraction|
UIViewAnimationOptionBeginFromCurrentState)
animations:^(void)
{
[selfresizeTextView:newSizeH];
}
completion:^(BOOL finished)
{
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:newSizeH];
}
}];
#endif
} else {
[UIViewbeginAnimations:@""context:nil];
[UIViewsetAnimationDuration:0.1f];
[UIViewsetAnimationDelegate:self];
[UIViewsetAnimationDidStopSelector:@selector(growDidStop)];
[UIViewsetAnimationBeginsFromCurrentState:YES];
[selfresizeTextView:newSizeH];
[UIViewcommitAnimations];
}
} else {
[selfresizeTextView:newSizeH];
// [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating
height changes.
// thanks to
Gwynne <http://blog.darkrainfall.org/>
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:newSizeH];
}
}
}
// if our new height is greater than the maxHeight
// sets not set the height or move things
// around and enable scrolling
if (newSizeH >= maxHeight)
{
if(!internalTextView.scrollEnabled){
internalTextView.scrollEnabled = YES;
[internalTextViewflashScrollIndicators];
}
} else {
internalTextView.scrollEnabled = NO;
}
}
if ([delegaterespondsToSelector:@selector(growingTextViewDidChange:)])
{
[delegategrowingTextViewDidChange:self];
}
}
-(void)resizeTextView:(NSInteger)newSizeH
{
if ([delegaterespondsToSelector:@selector(growingTextView:willChangeHeight:)])
{
[delegategrowingTextView:selfwillChangeHeight:newSizeH];
}
CGRect internalTextViewFrame = self.frame;
internalTextViewFrame.size.height =
newSizeH; // + padding
self.frame = internalTextViewFrame;
internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom;
internalTextViewFrame.origin.x = contentInset.left;
internalTextViewFrame.size.width = internalTextView.contentSize.width;
internalTextView.frame =
internalTextViewFrame;
}
-(void)growDidStop
{
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:self.frame.size.height];
}
}
-(void)touchesEnded:(NSSet *)touches
withEvent:(UIEvent *)event
{
[internalTextViewbecomeFirstResponder];
}
- (BOOL)becomeFirstResponder
{
[superbecomeFirstResponder];
return [self.internalTextViewbecomeFirstResponder];
}
-(BOOL)resignFirstResponder
{
[superresignFirstResponder];
return [internalTextViewresignFirstResponder];
}
-(BOOL)isFirstResponder
{
return [self.internalTextViewisFirstResponder];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark UITextView properties
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setText:(NSString *)newText
{
internalTextView.text =
newText;
// include this line to analyze the height of the textview.
// fix from Ankit Thakur
[selfperformSelector:@selector(textViewDidChange:) withObject:internalTextView];
}
-(NSString*) text
{
returninternalTextView.text;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setFont:(UIFont *)afont
{
internalTextView.font=
afont;
[selfsetMaxNumberOfLines:maxNumberOfLines];
[selfsetMinNumberOfLines:minNumberOfLines];
}
-(UIFont *)font
{
returninternalTextView.font;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setTextColor:(UIColor *)color
{
internalTextView.textColor =
color;
}
-(UIColor*)textColor{
returninternalTextView.textColor;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setBackgroundColor:(UIColor *)backgroundColor
{
[supersetBackgroundColor:backgroundColor];
internalTextView.backgroundColor =
backgroundColor;
}
-(UIColor*)backgroundColor
{
returninternalTextView.backgroundColor;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setTextAlignment:(UITextAlignment)aligment
{
internalTextView.textAlignment =
aligment;
}
-(UITextAlignment)textAlignment
{
returninternalTextView.textAlignment;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setSelectedRange:(NSRange)range
{
internalTextView.selectedRange =
range;
}
-(NSRange)selectedRange
{
returninternalTextView.selectedRange;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setEditable:(BOOL)beditable
{
internalTextView.editable =
beditable;
}
-(BOOL)isEditable
{
returninternalTextView.editable;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setReturnKeyType:(UIReturnKeyType)keyType
{
internalTextView.returnKeyType =
keyType;
}
-(UIReturnKeyType)returnKeyType
{
returninternalTextView.returnKeyType;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically
{
internalTextView.enablesReturnKeyAutomatically =
enablesReturnKeyAutomatically;
}
- (BOOL)enablesReturnKeyAutomatically
{
returninternalTextView.enablesReturnKeyAutomatically;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector
{
internalTextView.dataDetectorTypes =
datadetector;
}
-(UIDataDetectorTypes)dataDetectorTypes
{
returninternalTextView.dataDetectorTypes;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)hasText{
return [internalTextViewhasText];
}
- (void)scrollRangeToVisible:(NSRange)range
{
[internalTextViewscrollRangeToVisible:range];
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UITextViewDelegate
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldBeginEditing:)])
{
return [delegategrowingTextViewShouldBeginEditing:self];
} else {
returnYES;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldEndEditing:)])
{
return [delegategrowingTextViewShouldEndEditing:self];
} else {
returnYES;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidBeginEditing:)])
{
[delegategrowingTextViewDidBeginEditing:self];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidEndEditing:)])
{
[delegategrowingTextViewDidEndEditing:self];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)atext {
//weird 1 pixel bug when clicking backspace when textView is empty
if(![textView hasText]
&& [atext isEqualToString:@""]) returnNO;
//Added by bretdabaker: sometimes we want to handle this ourselves
if ([delegaterespondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)])
return [delegategrowingTextView:selfshouldChangeTextInRange:range replacementText:atext];
if ([atext isEqualToString:@"\n"])
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldReturn:)])
{
if (![delegateperformSelector:@selector(growingTextViewShouldReturn:) withObject:self])
{
returnYES;
} else {
[textView resignFirstResponder];
returnNO;
}
}
}
returnYES;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidChangeSelection:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidChangeSelection:)])
{
[delegategrowingTextViewDidChangeSelection:self];
}
}
@end
感谢开源的朋友。
第一个类:
#import <UIKit/UIKit.h>
@interface HPTextViewInternal
: UITextView {
NSString *placeholder;
UIColor *placeholderColor;
@private
UILabel *placeHolderLabel;
}
@property(nonatomic, retain) UILabel *placeHolderLabel;
@property(nonatomic, retain) NSString *placeholder;
@property(nonatomic, retain) UIColor *placeholderColor;
-(void)textChanged:(NSNotification*)notification;
@end
#import "HPTextViewInternal.h"
@implementation HPTextViewInternal
@synthesize placeHolderLabel;
@synthesize placeholder;
@synthesize placeholderColor;
- (void)dealloc
{
[[NSNotificationCenterdefaultCenter] removeObserver:self];
[placeHolderLabelrelease]; placeHolderLabel = nil;
[placeholderColorrelease]; placeholderColor = nil;
[placeholderrelease]; placeholder = nil;
[superdealloc];
}
- (void)awakeFromNib
{
[superawakeFromNib];
[selfsetPlaceholder:@""];
[selfsetPlaceholderColor:[UIColorlightGrayColor]];
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(textChanged:) name:UITextViewTextDidChangeNotificationobject:nil];
}
- (id)initWithFrame:(CGRect)frame
{
if(
(self =
[superinitWithFrame:frame])
)
{
[selfsetPlaceholder:@""];
[selfsetPlaceholderColor:[UIColorlightGrayColor]];
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(textChanged:) name:UITextViewTextDidChangeNotificationobject:nil];
}
returnself;
}
- (void)textChanged:(NSNotification *)notification
{
if([[selfplaceholder] length]
== 0)
{
return;
}
if([[selftext] length]
== 0)
{
[[selfviewWithTag:999] setAlpha:1];
}
else
{
[[selfviewWithTag:999] setAlpha:0];
}
}
- (void)drawRect:(CGRect)rect
{
if(
[[selfplaceholder] length]
> 0 )
{
if ( placeHolderLabel == nil )
{
placeHolderLabel =
[[UILabelalloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
placeHolderLabel.lineBreakMode = UILineBreakModeWordWrap;
placeHolderLabel.numberOfLines = 0;
placeHolderLabel.font = self.font;
placeHolderLabel.backgroundColor =
[UIColorclearColor];
placeHolderLabel.textColor = self.placeholderColor;
placeHolderLabel.alpha = 0;
placeHolderLabel.tag = 999;
[selfaddSubview:placeHolderLabel];
}
placeHolderLabel.text = self.placeholder;
[placeHolderLabelsizeToFit];
[selfsendSubviewToBack:placeHolderLabel];
}
if(
[[selftext] length]
== 0 &&
[[selfplaceholder] length]
> 0 )
{
[[selfviewWithTag:999] setAlpha:1];
}
[superdrawRect:rect];
}
-(void)setText:(NSString *)text
{
[supersetText:text];
[selftextChanged:nil];
BOOL originalValue
= self.scrollEnabled;
//If
one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO,
//setting
the text programatically will cause UIKit to search upwards until it finds a scrollView with scrollEnabled==yes
//then
scroll it erratically. Setting scrollEnabled temporarily to YES prevents this.
[selfsetScrollEnabled:YES];
[supersetText:text];
[selfsetScrollEnabled:originalValue];
}
-(void)setContentOffset:(CGPoint)s
{
if(self.tracking || self.decelerating){
//initiated by user...
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 0;
insets.top = 0;
self.contentInset =
insets;
} else {
float bottomOffset
= (self.contentSize.height - self.frame.size.height + self.contentInset.bottom);
if(s.y <
bottomOffset && self.scrollEnabled){
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 8;
insets.top = 0;
self.contentInset =
insets;
}
}
[supersetContentOffset:s];
}
-(void)setContentInset:(UIEdgeInsets)s
{
UIEdgeInsets insets
= s;
if(s.bottom>8)
insets.bottom = 0;
insets.top = 0;
[supersetContentInset:insets];
}
-(void)setContentSize:(CGSize)contentSize
{
//
is this an iOS5 bug? Need testing!
if(self.contentSize.height >
contentSize.height)
{
UIEdgeInsets insets
= self.contentInset;
insets.bottom = 0;
insets.top = 0;
self.contentInset =
insets;
}
[supersetContentSize:contentSize];
}
@end
第二个类:
#import <UIKit/UIKit.h>
@classHPGrowingTextView;
@classHPTextViewInternal;
@protocol HPGrowingTextViewDelegate
@optional
- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView
shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView;
- (void)growingTextView:(HPGrowingTextView *)growingTextView
willChangeHeight:(float)height;
- (void)growingTextView:(HPGrowingTextView *)growingTextView
didChangeHeight:(float)height;
- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView;
@end
@interface HPGrowingTextView : UIView <UITextViewDelegate>
{
HPTextViewInternal *internalTextView;
int minHeight;
int maxHeight;
//class properties
int maxNumberOfLines;
int minNumberOfLines;
BOOL animateHeightChange;
//uitextview properties
NSObject <HPGrowingTextViewDelegate>
*__unsafe_unretained delegate;
UITextAlignment textAlignment;
NSRange selectedRange;
BOOL editable;
UIDataDetectorTypes dataDetectorTypes;
UIReturnKeyType returnKeyType;
UIEdgeInsets contentInset;
}
//real class properties
@propertyint maxNumberOfLines;
@propertyint minNumberOfLines;
@propertyBOOL animateHeightChange;
@property (nonatomic, strong) UITextView *internalTextView;
//uitextview properties
@property(unsafe_unretained) NSObject<HPGrowingTextViewDelegate>
*delegate;
@property(nonatomic,strong) NSString *text;
@property(nonatomic,strong) UIFont *font;
@property(nonatomic,strong) UIColor *textColor;
@property(nonatomic) UITextAlignment textAlignment;
// default is UITextAlignmentLeft
@property(nonatomic) NSRange selectedRange;
// only ranges of length 0 are supported
@property(nonatomic,getter=isEditable) BOOL editable;
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA,
__IPHONE_3_0);
@property (nonatomic) UIReturnKeyType returnKeyType;
@property (assign) UIEdgeInsets contentInset;
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
//uitextview methods
//need others? use .internalTextView
- (BOOL)becomeFirstResponder;
- (BOOL)resignFirstResponder;
- (BOOL)isFirstResponder;
- (BOOL)hasText;
- (void)scrollRangeToVisible:(NSRange)range;
//设置Placeholder属性
-(void)settingPlaceholder:(NSString *)string;
@end
#import "HPGrowingTextView.h"
#import "HPTextViewInternal.h"
@interface HPGrowingTextView(private)
-(void)commonInitialiser;
-(void)resizeTextView:(NSInteger)newSizeH;
-(void)growDidStop;
@end
@implementation HPGrowingTextView
@synthesize internalTextView;
@synthesize delegate;
@synthesize font;
@synthesize textColor;
@synthesize textAlignment;
@synthesize selectedRange;
@synthesize editable;
@synthesize dataDetectorTypes;
@synthesize animateHeightChange;
@synthesize returnKeyType;
// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [superinitWithCoder:aDecoder]))
{
[selfcommonInitialiser];
}
returnself;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [superinitWithFrame:frame]))
{
[selfcommonInitialiser];
}
returnself;
}
-(void)commonInitialiser
{
// Initialization code
CGRect r = self.frame;
r.origin.y = 0;
r.origin.x = 0;
internalTextView = [[HPTextViewInternalalloc] initWithFrame:r];
internalTextView.delegate = self;
internalTextView.scrollEnabled = NO;
internalTextView.font =
[UIFontfontWithName:@"Helvetica"size:13];
internalTextView.contentInset = UIEdgeInsetsZero;
internalTextView.showsHorizontalScrollIndicator = NO;
internalTextView.text = @"-";
[selfaddSubview:internalTextView];
minHeight = internalTextView.frame.size.height;
minNumberOfLines = 1;
animateHeightChange = YES;
internalTextView.text = @"";
//设置Placeholder属性
[selfsetMaxNumberOfLines:3];
}
-(void)settingPlaceholder:(NSString *)string
{
internalTextView.placeholder =
string;
}
-(CGSize)sizeThatFits:(CGSize)size
{
if (self.text.length == 0)
{
size.height = minHeight;
}
return size;
}
-(void)layoutSubviews
{
[superlayoutSubviews];
CGRect r = self.bounds;
r.origin.y = 0;
r.origin.x = contentInset.left;
r.size.width -= contentInset.left + contentInset.right;
internalTextView.frame =
r;
}
-(void)setContentInset:(UIEdgeInsets)inset
{
contentInset = inset;
CGRect r = self.frame;
r.origin.y = inset.top -
inset.bottom;
r.origin.x = inset.left;
r.size.width -=
inset.left + inset.right;
internalTextView.frame =
r;
[selfsetMaxNumberOfLines:maxNumberOfLines];
[selfsetMinNumberOfLines:minNumberOfLines];
}
-(UIEdgeInsets)contentInset
{
returncontentInset;
}
-(void)setMaxNumberOfLines:(int)n
{
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
NSString *saveText = internalTextView.text,
*newText = @"-";
internalTextView.delegate = nil;
internalTextView.hidden = YES;
for (int i = 1;
i < n; ++i)
newText = [newText stringByAppendingString:@"\n|W|"];
internalTextView.text =
newText;
maxHeight = internalTextView.contentSize.height;
internalTextView.text =
saveText;
internalTextView.hidden = NO;
internalTextView.delegate = self;
[selfsizeToFit];
maxNumberOfLines = n;
}
-(int)maxNumberOfLines
{
returnmaxNumberOfLines;
}
-(void)setMinNumberOfLines:(int)m
{
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
NSString *saveText = internalTextView.text,
*newText = @"-";
internalTextView.delegate = nil;
internalTextView.hidden = YES;
for (int i = 1;
i < m; ++i)
newText = [newText stringByAppendingString:@"\n|W|"];
internalTextView.text =
newText;
minHeight = internalTextView.contentSize.height;
internalTextView.text =
saveText;
internalTextView.hidden = NO;
internalTextView.delegate = self;
[selfsizeToFit];
minNumberOfLines = m;
}
-(int)minNumberOfLines
{
returnminNumberOfLines;
}
- (void)textViewDidChange:(UITextView *)textView
{
//size of content, so we can set the frame of self
NSInteger newSizeH = internalTextView.contentSize.height;
if(newSizeH < minHeight ||
!internalTextView.hasText) newSizeH = minHeight; //not
smalles than minHeight
if (internalTextView.frame.size.height > maxHeight)
newSizeH = maxHeight; // not taller than maxHeight
if (internalTextView.frame.size.height !=
newSizeH)
{
// [fixed] Pasting too much text into the view failed to fire the height change,
// thanks to Gwynne
<http://blog.darkrainfall.org/>
if (newSizeH
> maxHeight && internalTextView.frame.size.height <= maxHeight)
{
newSizeH = maxHeight;
}
if (newSizeH <= maxHeight)
{
if(animateHeightChange)
{
if ([UIViewresolveClassMethod:@selector(animateWithDuration:animations:)])
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
[UIViewanimateWithDuration:0.1f
delay:0
options:(UIViewAnimationOptionAllowUserInteraction|
UIViewAnimationOptionBeginFromCurrentState)
animations:^(void)
{
[selfresizeTextView:newSizeH];
}
completion:^(BOOL finished)
{
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:newSizeH];
}
}];
#endif
} else {
[UIViewbeginAnimations:@""context:nil];
[UIViewsetAnimationDuration:0.1f];
[UIViewsetAnimationDelegate:self];
[UIViewsetAnimationDidStopSelector:@selector(growDidStop)];
[UIViewsetAnimationBeginsFromCurrentState:YES];
[selfresizeTextView:newSizeH];
[UIViewcommitAnimations];
}
} else {
[selfresizeTextView:newSizeH];
// [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating
height changes.
// thanks to
Gwynne <http://blog.darkrainfall.org/>
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:newSizeH];
}
}
}
// if our new height is greater than the maxHeight
// sets not set the height or move things
// around and enable scrolling
if (newSizeH >= maxHeight)
{
if(!internalTextView.scrollEnabled){
internalTextView.scrollEnabled = YES;
[internalTextViewflashScrollIndicators];
}
} else {
internalTextView.scrollEnabled = NO;
}
}
if ([delegaterespondsToSelector:@selector(growingTextViewDidChange:)])
{
[delegategrowingTextViewDidChange:self];
}
}
-(void)resizeTextView:(NSInteger)newSizeH
{
if ([delegaterespondsToSelector:@selector(growingTextView:willChangeHeight:)])
{
[delegategrowingTextView:selfwillChangeHeight:newSizeH];
}
CGRect internalTextViewFrame = self.frame;
internalTextViewFrame.size.height =
newSizeH; // + padding
self.frame = internalTextViewFrame;
internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom;
internalTextViewFrame.origin.x = contentInset.left;
internalTextViewFrame.size.width = internalTextView.contentSize.width;
internalTextView.frame =
internalTextViewFrame;
}
-(void)growDidStop
{
if ([delegaterespondsToSelector:@selector(growingTextView:didChangeHeight:)])
{
[delegategrowingTextView:selfdidChangeHeight:self.frame.size.height];
}
}
-(void)touchesEnded:(NSSet *)touches
withEvent:(UIEvent *)event
{
[internalTextViewbecomeFirstResponder];
}
- (BOOL)becomeFirstResponder
{
[superbecomeFirstResponder];
return [self.internalTextViewbecomeFirstResponder];
}
-(BOOL)resignFirstResponder
{
[superresignFirstResponder];
return [internalTextViewresignFirstResponder];
}
-(BOOL)isFirstResponder
{
return [self.internalTextViewisFirstResponder];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark UITextView properties
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setText:(NSString *)newText
{
internalTextView.text =
newText;
// include this line to analyze the height of the textview.
// fix from Ankit Thakur
[selfperformSelector:@selector(textViewDidChange:) withObject:internalTextView];
}
-(NSString*) text
{
returninternalTextView.text;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setFont:(UIFont *)afont
{
internalTextView.font=
afont;
[selfsetMaxNumberOfLines:maxNumberOfLines];
[selfsetMinNumberOfLines:minNumberOfLines];
}
-(UIFont *)font
{
returninternalTextView.font;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setTextColor:(UIColor *)color
{
internalTextView.textColor =
color;
}
-(UIColor*)textColor{
returninternalTextView.textColor;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setBackgroundColor:(UIColor *)backgroundColor
{
[supersetBackgroundColor:backgroundColor];
internalTextView.backgroundColor =
backgroundColor;
}
-(UIColor*)backgroundColor
{
returninternalTextView.backgroundColor;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setTextAlignment:(UITextAlignment)aligment
{
internalTextView.textAlignment =
aligment;
}
-(UITextAlignment)textAlignment
{
returninternalTextView.textAlignment;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setSelectedRange:(NSRange)range
{
internalTextView.selectedRange =
range;
}
-(NSRange)selectedRange
{
returninternalTextView.selectedRange;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setEditable:(BOOL)beditable
{
internalTextView.editable =
beditable;
}
-(BOOL)isEditable
{
returninternalTextView.editable;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setReturnKeyType:(UIReturnKeyType)keyType
{
internalTextView.returnKeyType =
keyType;
}
-(UIReturnKeyType)returnKeyType
{
returninternalTextView.returnKeyType;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically
{
internalTextView.enablesReturnKeyAutomatically =
enablesReturnKeyAutomatically;
}
- (BOOL)enablesReturnKeyAutomatically
{
returninternalTextView.enablesReturnKeyAutomatically;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-(void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector
{
internalTextView.dataDetectorTypes =
datadetector;
}
-(UIDataDetectorTypes)dataDetectorTypes
{
returninternalTextView.dataDetectorTypes;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)hasText{
return [internalTextViewhasText];
}
- (void)scrollRangeToVisible:(NSRange)range
{
[internalTextViewscrollRangeToVisible:range];
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UITextViewDelegate
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldBeginEditing:)])
{
return [delegategrowingTextViewShouldBeginEditing:self];
} else {
returnYES;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldEndEditing:)])
{
return [delegategrowingTextViewShouldEndEditing:self];
} else {
returnYES;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidBeginEditing:)])
{
[delegategrowingTextViewDidBeginEditing:self];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidEndEditing:)])
{
[delegategrowingTextViewDidEndEditing:self];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)atext {
//weird 1 pixel bug when clicking backspace when textView is empty
if(![textView hasText]
&& [atext isEqualToString:@""]) returnNO;
//Added by bretdabaker: sometimes we want to handle this ourselves
if ([delegaterespondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)])
return [delegategrowingTextView:selfshouldChangeTextInRange:range replacementText:atext];
if ([atext isEqualToString:@"\n"])
{
if ([delegaterespondsToSelector:@selector(growingTextViewShouldReturn:)])
{
if (![delegateperformSelector:@selector(growingTextViewShouldReturn:) withObject:self])
{
returnYES;
} else {
[textView resignFirstResponder];
returnNO;
}
}
}
returnYES;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)textViewDidChangeSelection:(UITextView *)textView
{
if ([delegaterespondsToSelector:@selector(growingTextViewDidChangeSelection:)])
{
[delegategrowingTextViewDidChangeSelection:self];
}
}
@end
感谢开源的朋友。
相关文章推荐
- 解决UITextView的Placeholder属性
- 解决IE下不支持placeholder属性可以根据自己的需要去扩展.
- UITextView添加placeholder属性
- HTML 5 <input> placeholder 属性兼容性解决办法
- IE不支持HTML5表单属性placeholder的解决办法
- javascript 解决IE8 兼容 placeholder 属性 含password
- UITextView添加placeholder属性
- 解决IE下不支持placeholder属性可以根据自己的需要去扩展
- HTML5 解决表单输入提示 placeholder 属性
- ie placeholder属性的兼容性问题解决方法
- IM模块--UItextView带有placeholder属性,自动调节高度
- 解决IE下输入框不支持placeholder属性
- iOS控件UITextView 实现placeholder效果和解决UITableView键盘遮挡
- UItextview 怎么实现placeholder属性
- 自定义 UITextView 的 placeholder 属性
- UITextView的placeholder属性
- 解决IE不支持HTML5表单属性placeholder的问题
- ie浏览器下placeholder属性显示不出来的两种解决方式
- IE678910不兼容H5的placeholder属性,需要JS解决
- jquery 解决ie9及以下版本不支持placeholder属性