Skip to content

Commit

Permalink
Rip out selection stuff and add ability to set highlight attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
Collin Ruffenach committed Mar 4, 2014
1 parent 0bc2eb8 commit bffc69a
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 91 deletions.
3 changes: 1 addition & 2 deletions STTweetLabel/STTweetLabel.h
Expand Up @@ -16,15 +16,14 @@ typedef enum {


@property (nonatomic, strong) NSArray *validProtocols; @property (nonatomic, strong) NSArray *validProtocols;
@property (nonatomic, assign) BOOL leftToRight; @property (nonatomic, assign) BOOL leftToRight;
@property (nonatomic, assign) BOOL textSelectable;
@property (nonatomic, strong) UIColor *selectionColor;
@property (nonatomic, copy) void (^detectionBlock)(STTweetHotWord hotWord, NSString *string, NSString *protocol, NSRange range); @property (nonatomic, copy) void (^detectionBlock)(STTweetHotWord hotWord, NSString *string, NSString *protocol, NSRange range);


- (void)setAttributes:(NSDictionary *)attributes; - (void)setAttributes:(NSDictionary *)attributes;
- (void)setAttributes:(NSDictionary *)attributes hotWord:(STTweetHotWord)hotWord; - (void)setAttributes:(NSDictionary *)attributes hotWord:(STTweetHotWord)hotWord;


- (NSDictionary *)attributes; - (NSDictionary *)attributes;
- (NSDictionary *)attributesForHotWord:(STTweetHotWord)hotWord; - (NSDictionary *)attributesForHotWord:(STTweetHotWord)hotWord;
- (void)setHighlightedAttributes:(NSDictionary *)attributes hotWord:(STTweetHotWord)hotWord;


- (CGSize)suggestedFrameSizeToFitEntireStringConstraintedToWidth:(CGFloat)width; - (CGSize)suggestedFrameSizeToFitEntireStringConstraintedToWidth:(CGFloat)width;


Expand Down
150 changes: 68 additions & 82 deletions STTweetLabel/STTweetLabel.m
Expand Up @@ -29,6 +29,9 @@ @interface STTweetLabel () <UITextViewDelegate>
@property (nonatomic, strong) NSDictionary *attributesHashtag; @property (nonatomic, strong) NSDictionary *attributesHashtag;
@property (nonatomic, strong) NSDictionary *attributesLink; @property (nonatomic, strong) NSDictionary *attributesLink;


@property (nonatomic, strong) NSDictionary *highlightedAttributesLink;
@property (nonatomic, assign) id highlightedWord;

@property (strong) UITextView *textView; @property (strong) UITextView *textView;


- (void)setupLabel; - (void)setupLabel;
Expand All @@ -40,7 +43,6 @@ - (void)updateText;


@implementation STTweetLabel { @implementation STTweetLabel {
BOOL _isTouchesMoved; BOOL _isTouchesMoved;
NSRange _selectableRange;
int _firstCharIndex; int _firstCharIndex;
CGPoint _firstTouchLocation; CGPoint _firstTouchLocation;
} }
Expand All @@ -63,26 +65,6 @@ - (void)awakeFromNib {
[self setupLabel]; [self setupLabel];
} }


#pragma mark -
#pragma mark Responder

- (BOOL)canBecomeFirstResponder {
return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return (action == @selector(copy:));
}

- (void)copy:(id)sender {
[[UIPasteboard generalPasteboard] setString:[_cleanText substringWithRange:_selectableRange]];

@try {
[_textStorage removeAttribute:NSBackgroundColorAttributeName range:_selectableRange];
} @catch (NSException *exception) {
}
}

#pragma mark - #pragma mark -
#pragma mark Setup #pragma mark Setup


Expand All @@ -94,8 +76,6 @@ - (void)setupLabel {
[self setNumberOfLines:0]; [self setNumberOfLines:0];


_leftToRight = YES; _leftToRight = YES;
_textSelectable = YES;
_selectionColor = [UIColor colorWithWhite:0.9 alpha:1.0];


_attributesText = @{NSForegroundColorAttributeName: self.textColor, NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14.0]}; _attributesText = @{NSForegroundColorAttributeName: self.textColor, NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14.0]};
_attributesHandle = @{NSForegroundColorAttributeName: [UIColor redColor], NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14.0]}; _attributesHandle = @{NSForegroundColorAttributeName: [UIColor redColor], NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14.0]};
Expand Down Expand Up @@ -305,6 +285,34 @@ - (void)setAttributes:(NSDictionary *)attributes hotWord:(STTweetHotWord)hotWord
} }
} }


- (void)setHighlightedAttributes:(NSDictionary *)attributes hotWord:(STTweetHotWord)hotWord {
if (!attributes[NSFontAttributeName]) {
NSMutableDictionary *copy = [attributes mutableCopy];
copy[NSFontAttributeName] = self.font;
attributes = [NSDictionary dictionaryWithDictionary:copy];
}

if (!attributes[NSForegroundColorAttributeName]) {
NSMutableDictionary *copy = [attributes mutableCopy];
copy[NSForegroundColorAttributeName] = self.textColor;
attributes = [NSDictionary dictionaryWithDictionary:copy];
}

switch (hotWord) {
case STTweetHandle:
// _attributesHandle = attributes;
break;
case STTweetHashtag:
// _attributesHashtag = attributes;
break;
case STTweetLink:
_highlightedAttributesLink = attributes;
break;
default:
break;
}
}

- (void)setLeftToRight:(BOOL)leftToRight { - (void)setLeftToRight:(BOOL)leftToRight {
_leftToRight = leftToRight; _leftToRight = leftToRight;


Expand Down Expand Up @@ -367,82 +375,60 @@ - (BOOL)isLeftToRight {
#pragma mark - #pragma mark -
#pragma mark Retrieve word after touch event #pragma mark Retrieve word after touch event


- (void)clearHighlightedWord {
if (_highlightedWord) {
NSRange range = [[_highlightedWord objectForKey:@"range"] rangeValue];
self.highlightedWord = nil;
[_textStorage removeAttributes:_highlightedAttributesLink range:range];
[_textStorage addAttributes:_attributesLink range:range];
self.highlightedWord = nil;
}
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event]; [super touchesBegan:touches withEvent:event];

[self clearHighlightedWord];
_isTouchesMoved = NO; int charIndex = (int)[self charIndexAtLocation:[[touches anyObject] locationInView:_textView]];

__block typeof(self) blockSelf = self;
@try { [_rangesOfHotWords enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[_textStorage removeAttribute:NSBackgroundColorAttributeName range:_selectableRange]; NSRange range = [[obj objectForKey:@"range"] rangeValue];
} @catch (NSException *exception) { if (NSLocationInRange(charIndex, range)) {
} blockSelf.highlightedWord = obj;

[blockSelf.textStorage removeAttributes:_attributesLink
_selectableRange = NSMakeRange(0, 0); range:range];
_firstTouchLocation = [[touches anyObject] locationInView:_textView]; [blockSelf.textStorage addAttributes:_highlightedAttributesLink
range:range];
*stop = YES;
}
}];
} }


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event]; [super touchesMoved:touches withEvent:event];

if (_highlightedWord) {
if (!_textSelectable) { int charIndex = (int)[self charIndexAtLocation:[[touches anyObject] locationInView:_textView]];
UIMenuController *menuController = [UIMenuController sharedMenuController]; NSRange range = [[_highlightedWord objectForKey:@"range"] rangeValue];
[menuController setMenuVisible:NO animated:YES]; if (!NSLocationInRange(charIndex, range)) {

[self clearHighlightedWord];
return; }
}

_isTouchesMoved = YES;

int charIndex = (int)[self charIndexAtLocation:[[touches anyObject] locationInView:_textView]];

@try {
[_textStorage removeAttribute:NSBackgroundColorAttributeName range:_selectableRange];
} @catch (NSException *exception) {
}

if (_selectableRange.length == 0) {
_selectableRange = NSMakeRange(charIndex, 1);
_firstCharIndex = charIndex;
} else if (charIndex > _firstCharIndex) {
_selectableRange = NSMakeRange(_firstCharIndex, charIndex - _firstCharIndex + 1);
} else if (charIndex < _firstCharIndex) {
_firstTouchLocation = [[touches anyObject] locationInView:_textView];

_selectableRange = NSMakeRange(charIndex, _firstCharIndex - charIndex);
}

@try {
[_textStorage addAttribute:NSBackgroundColorAttributeName value:_selectionColor range:_selectableRange];
} @catch (NSException *exception) {
} }
} }


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event]; [super touchesEnded:touches withEvent:event];

CGPoint touchLocation = [[touches anyObject] locationInView:self]; CGPoint touchLocation = [[touches anyObject] locationInView:self];

if (!CGRectContainsPoint(_textView.frame, touchLocation)) return;
if (_isTouchesMoved) {
UIMenuController *menuController = [UIMenuController sharedMenuController];
[menuController setTargetRect:CGRectMake(_firstTouchLocation.x, _firstTouchLocation.y, 1.0, 1.0) inView:self];
[menuController setMenuVisible:YES animated:YES];

[self becomeFirstResponder];

return;
}

if (!CGRectContainsPoint(_textView.frame, touchLocation))
return;


int charIndex = (int)[self charIndexAtLocation:[[touches anyObject] locationInView:_textView]]; int charIndex = (int)[self charIndexAtLocation:[[touches anyObject] locationInView:_textView]];


[_rangesOfHotWords enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [_rangesOfHotWords enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSRange range = [[obj objectForKey:@"range"] rangeValue]; NSRange range = [[obj objectForKey:@"range"] rangeValue];

if (NSLocationInRange(charIndex, range)) {
if (charIndex >= range.location && charIndex < range.location + range.length) { [self clearHighlightedWord];
_detectionBlock((STTweetHotWord)[[obj objectForKey:@"hotWord"] intValue], [_cleanText substringWithRange:range], [obj objectForKey:@"protocol"], range); _detectionBlock((STTweetHotWord)[[obj objectForKey:@"hotWord"] intValue],

[_cleanText substringWithRange:range],
[obj objectForKey:@"protocol"],
range);
*stop = YES; *stop = YES;
} }
}]; }];
Expand Down
1 change: 1 addition & 0 deletions STTweetLabel/STTweetTextStorage.h
Expand Up @@ -14,5 +14,6 @@


- (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range; - (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;
- (void)removeAttribute:(NSString *)name range:(NSRange)range; - (void)removeAttribute:(NSString *)name range:(NSRange)range;
- (void)removeAttributes:(NSDictionary*)attributes range:(NSRange)range;


@end @end
7 changes: 7 additions & 0 deletions STTweetLabel/STTweetTextStorage.m
Expand Up @@ -55,6 +55,13 @@ - (void)removeAttribute:(NSString *)name range:(NSRange)range {
[self endEditing]; [self endEditing];
} }


- (void)removeAttributes:(NSDictionary*)attributes range:(NSRange)range {
__block typeof(self) blockSelf = self;
[attributes enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[blockSelf removeAttribute:key range:range];
}];
}

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string { - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string {
[self beginEditing]; [self beginEditing];
[_backingStore replaceCharactersInRange:range withString:string]; [_backingStore replaceCharactersInRange:range withString:string];
Expand Down
Expand Up @@ -5,34 +5,34 @@
<key>IDESourceControlProjectFavoriteDictionaryKey</key> <key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/> <false/>
<key>IDESourceControlProjectIdentifier</key> <key>IDESourceControlProjectIdentifier</key>
<string>07C12E3B-50A0-45B9-AA7F-923C04908480</string> <string>D000AC98-092C-4EA5-A0DD-BFACE75BE8F7</string>
<key>IDESourceControlProjectName</key> <key>IDESourceControlProjectName</key>
<string>STTweetLabelExample</string> <string>STTweetLabelExample</string>
<key>IDESourceControlProjectOriginsDictionary</key> <key>IDESourceControlProjectOriginsDictionary</key>
<dict> <dict>
<key>D2B5469B-FFE8-44F3-9BAD-28F0412E4E1F</key> <key>093123D7-6A52-4172-A7A0-C2A905951119</key>
<string>ssh://github.com/SebastienThiebaud/STTweetLabel.git</string> <string>ssh://github.com/cruffenach/STTweetLabel.git</string>
</dict> </dict>
<key>IDESourceControlProjectPath</key> <key>IDESourceControlProjectPath</key>
<string>STTweetLabelExample/STTweetLabelExample.xcodeproj/project.xcworkspace</string> <string>STTweetLabelExample/STTweetLabelExample.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key> <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict> <dict>
<key>D2B5469B-FFE8-44F3-9BAD-28F0412E4E1F</key> <key>093123D7-6A52-4172-A7A0-C2A905951119</key>
<string>../../..</string> <string>../../..</string>
</dict> </dict>
<key>IDESourceControlProjectURL</key> <key>IDESourceControlProjectURL</key>
<string>ssh://github.com/SebastienThiebaud/STTweetLabel.git</string> <string>ssh://github.com/cruffenach/STTweetLabel.git</string>
<key>IDESourceControlProjectVersion</key> <key>IDESourceControlProjectVersion</key>
<integer>110</integer> <integer>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key> <key>IDESourceControlProjectWCCIdentifier</key>
<string>D2B5469B-FFE8-44F3-9BAD-28F0412E4E1F</string> <string>093123D7-6A52-4172-A7A0-C2A905951119</string>
<key>IDESourceControlProjectWCConfigurations</key> <key>IDESourceControlProjectWCConfigurations</key>
<array> <array>
<dict> <dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key> <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string> <string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key> <key>IDESourceControlWCCIdentifierKey</key>
<string>D2B5469B-FFE8-44F3-9BAD-28F0412E4E1F</string> <string>093123D7-6A52-4172-A7A0-C2A905951119</string>
<key>IDESourceControlWCCName</key> <key>IDESourceControlWCCName</key>
<string>STTweetLabel</string> <string>STTweetLabel</string>
</dict> </dict>
Expand Down
2 changes: 2 additions & 0 deletions STTweetLabelExample/STTweetLabelExample/STViewController.m
Expand Up @@ -31,6 +31,8 @@ - (void)viewDidLoad {
tweetLabel.textAlignment = NSTextAlignmentLeft; tweetLabel.textAlignment = NSTextAlignmentLeft;
[self.view addSubview:tweetLabel]; [self.view addSubview:tweetLabel];


[tweetLabel setHighlightedAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} hotWord:STTweetLink];

CGSize size = [tweetLabel suggestedFrameSizeToFitEntireStringConstraintedToWidth:tweetLabel.frame.size.width]; CGSize size = [tweetLabel suggestedFrameSizeToFitEntireStringConstraintedToWidth:tweetLabel.frame.size.width];
CGRect frame = tweetLabel.frame; CGRect frame = tweetLabel.frame;
frame.size.height = size.height; frame.size.height = size.height;
Expand Down

0 comments on commit bffc69a

Please sign in to comment.