Skip to content

Instantly share code, notes, and snippets.

@agiletortoise
Last active December 24, 2015 00:09
Show Gist options
  • Star 87 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save agiletortoise/a24ccbf2d33aafb2abc1 to your computer and use it in GitHub Desktop.
Save agiletortoise/a24ccbf2d33aafb2abc1 to your computer and use it in GitHub Desktop.
UITextView subclass to address text selection issues in iOS 7
// 2013/09/26 by Greg Pierce
//
// Example code for workarounds to text selection issues in iOS 7 UITextView
// This code is culled from several examples seen elsewhere
// This code may totally crash your app...no guarantees.
//
// Using this UITextView subclass significantly improves the ability to do basic text selection
// in standard UITextViews on iOS 7...particular avoiding failures to selection
// empty lines and trying to select line endings in general.
//
// Comments on improving this workaround are welcome! @agiletortoise
#import "ATTextView.h"
@implementation ATTextView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//
}
return self;
}
- (CGRect)firstRectForRange:(UITextRange *)range
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
CGRect r1= [self caretRectForPosition:[self positionWithinRange:range farthestInDirection:UITextLayoutDirectionRight]];
CGRect r2= [self caretRectForPosition:[self positionWithinRange:range farthestInDirection:UITextLayoutDirectionLeft]];
return CGRectUnion(r1,r2);
}
return [super firstRectForRange:range];
}
- (NSUInteger)characterIndexForPoint:(CGPoint)point
{
if (self.text.length == 0) {
return 0;
}
CGRect r1;
if ([[self.text substringFromIndex:self.text.length-1] isEqualToString:@"\n"]) {
r1 = [super caretRectForPosition:[super positionFromPosition:self.endOfDocument offset:-1]];
CGRect sr = [super caretRectForPosition:[super positionFromPosition:self.beginningOfDocument offset:0]];
r1.origin.x = sr.origin.x;
r1.origin.y += self.font.lineHeight;
} else {
r1 = [super caretRectForPosition:[super positionFromPosition:self.endOfDocument offset:0]];
}
if ((point.x > r1.origin.x && point.y >= r1.origin.y) || point.y >= r1.origin.y+r1.size.height) {
return [super offsetFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
}
CGFloat fraction;
NSUInteger index = [self.textStorage.layoutManagers[0] characterIndexForPoint:point inTextContainer:self.textContainer fractionOfDistanceBetweenInsertionPoints:&fraction];
return index;
}
- (UITextPosition *)closestPositionToPoint:(CGPoint)point
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
point.y -= self.font.lineHeight/2;
NSUInteger index = [self characterIndexForPoint:point];
UITextPosition *pos = [self positionFromPosition:self.beginningOfDocument offset:index];
return pos;
}
return [super closestPositionToPoint:point];
}
- (void)scrollRangeToVisible:(NSRange)range
{
[super scrollRangeToVisible:range];
if (self.layoutManager.extraLineFragmentTextContainer != nil && self.selectedRange.location == range.location)
{
CGRect caretRect = [self caretRectForPosition:self.selectedTextRange.start];
[self scrollRectToVisible:caretRect animated:YES];
}
}
@end
@senindeveloper
Copy link

Its very close!!

But only one thing. After resign first responder cursor stays at top of text view, but not on current position. How can I change it?

@nolanw
Copy link

nolanw commented Oct 18, 2013

What is the point of the -firstRectForRange: override? I can't find a difference whether I include it or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment