您的位置:首页 > 产品设计 > UI/UE

解决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

感谢开源的朋友。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: