Skip to content
This repository was archived by the owner on Apr 22, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions class/HPGrowingTextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@

BOOL animateHeightChange;
NSTimeInterval animationDuration;
BOOL willRefreshHeight;

//uitextview properties
NSObject <HPGrowingTextViewDelegate> *__unsafe_unretained delegate;
Expand Down
168 changes: 93 additions & 75 deletions class/HPGrowingTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ -(void)commonInitialiser

animateHeightChange = YES;
animationDuration = 0.1f;
willRefreshHeight = NO;

internalTextView.text = @"";

Expand Down Expand Up @@ -253,97 +254,114 @@ - (void)setPlaceholderColor:(UIColor *)placeholderColor

- (void)textViewDidChange:(UITextView *)textView
{
[self refreshHeight];
[self doRefreshHeight];
}

- (void)refreshHeight
- (void)doRefreshHeight
{
//size of content, so we can set the frame of self
NSInteger newSizeH = [self measureHeight];
if (newSizeH < minHeight || !internalTextView.hasText) {
newSizeH = minHeight; //not smalles than minHeight
}
else if (maxHeight && newSizeH > maxHeight) {
newSizeH = maxHeight; // not taller than maxHeight
// if we use korean keyboard, UITextView occasionally fires 2 textViewDidChange events simultaneously.
// for example, there is "버그버그ㅂ". we presse the "ㅓ" key. then text is changed to "버그버그버"
// but UITextView fires 2 textViewDidChange events. The first event is "버그버그ㅂ" to "버그버그". The second event is "버그버그" to "버그버그버".
// so we should use the last event of these events.
if (!willRefreshHeight) {
willRefreshHeight = YES;
[self performSelector:@selector(refreshHeight) withObject:nil afterDelay:0];
}

if (internalTextView.frame.size.height != 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;
[internalTextView flashScrollIndicators];
}

} else {
internalTextView.scrollEnabled = NO;
}

- (void)refreshHeight
{
@try {
//size of content, so we can set the frame of self
NSInteger newSizeH = [self measureHeight];
if (newSizeH < minHeight || !internalTextView.hasText) {
newSizeH = minHeight; //not smalles than minHeight
}
else if (maxHeight && newSizeH > maxHeight) {
newSizeH = maxHeight; // not taller than maxHeight
}

// [fixed] Pasting too much text into the view failed to fire the height change,
// thanks to Gwynne <http://blog.darkrainfall.org/>
if (newSizeH <= maxHeight)
{
if(animateHeightChange) {
if (internalTextView.frame.size.height != 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;
[internalTextView flashScrollIndicators];
}

if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) {
} else {
internalTextView.scrollEnabled = NO;
}

// [fixed] Pasting too much text into the view failed to fire the height change,
// thanks to Gwynne <http://blog.darkrainfall.org/>
if (newSizeH <= maxHeight)
{
if(animateHeightChange) {

if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
[UIView animateWithDuration:animationDuration
delay:0
options:(UIViewAnimationOptionAllowUserInteraction|
UIViewAnimationOptionBeginFromCurrentState)
animations:^(void) {
[self resizeTextView:newSizeH];
}
completion:^(BOOL finished) {
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
[delegate growingTextView:self didChangeHeight:newSizeH];
[UIView animateWithDuration:animationDuration
delay:0
options:(UIViewAnimationOptionAllowUserInteraction|
UIViewAnimationOptionBeginFromCurrentState)
animations:^(void) {
[self resizeTextView:newSizeH];
}
}];
completion:^(BOOL finished) {
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
[delegate growingTextView:self didChangeHeight:newSizeH];
}
}];
#endif
} else {
[UIView beginAnimations:@"" context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(growDidStop)];
[UIView setAnimationBeginsFromCurrentState:YES];
[self resizeTextView:newSizeH];
[UIView commitAnimations];
}
} else {
[UIView beginAnimations:@"" context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(growDidStop)];
[UIView setAnimationBeginsFromCurrentState:YES];
[self resizeTextView:newSizeH];
[UIView commitAnimations];
// [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating height changes.
// thanks to Gwynne <http://blog.darkrainfall.org/>

if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
[delegate growingTextView:self didChangeHeight:newSizeH];
}
}
} else {
[self resizeTextView: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 ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
[delegate growingTextView:self didChangeHeight:newSizeH];
}
}
}
}
// Display (or not) the placeholder string

BOOL wasDisplayingPlaceholder = internalTextView.displayPlaceHolder;
internalTextView.displayPlaceHolder = self.internalTextView.text.length == 0;

if (wasDisplayingPlaceholder != internalTextView.displayPlaceHolder) {
[internalTextView setNeedsDisplay];
}
// Display (or not) the placeholder string

BOOL wasDisplayingPlaceholder = internalTextView.displayPlaceHolder;
internalTextView.displayPlaceHolder = self.internalTextView.text.length == 0;

if (wasDisplayingPlaceholder != internalTextView.displayPlaceHolder) {
[internalTextView setNeedsDisplay];
}


// scroll to caret (needed on iOS7)
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
[self performSelector:@selector(resetScrollPositionForIOS7) withObject:nil afterDelay:0.1f];
}

// Tell the delegate that the text view changed
if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) {
[delegate growingTextViewDidChange:self];
}
}


// scroll to caret (needed on iOS7)
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
[self performSelector:@selector(resetScrollPositionForIOS7) withObject:nil afterDelay:0.1f];
@finally {
willRefreshHeight = NO;
}

// Tell the delegate that the text view changed
if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) {
[delegate growingTextViewDidChange:self];
}
}

// Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
Expand Down