-
-
Save agiletortoise/a24ccbf2d33aafb2abc1 to your computer and use it in GitHub Desktop.
UITextView subclass to address text selection issues in iOS 7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
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
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?