From cf48daccc9bc4803cb427796bb70dd2fa463e2ae Mon Sep 17 00:00:00 2001 From: "Juan V. Guerrero" Date: Thu, 29 Nov 2012 21:58:05 -0500 Subject: [PATCH] * Improving JSTokenButton customisation options * Adding delegate methods so we can find out if a JSTokenButton has been touched or if it has been toggled --- JSTokenField.xcodeproj/project.pbxproj | 16 ++++ JSTokenField/DemoViewController.m | 16 +++- JSTokenField/JSTokenButton.h | 11 ++- JSTokenField/JSTokenButton.m | 100 +++++++++++++++++++++-- JSTokenField/JSTokenField.h | 7 ++ JSTokenField/JSTokenField.m | 77 +++++++++++++++-- JSTokenField/tokenHighlightedDark.png | Bin 0 -> 3584 bytes JSTokenField/tokenHighlightedDark@2x.png | Bin 0 -> 4276 bytes JSTokenField/tokenNormalDark.png | Bin 0 -> 3623 bytes JSTokenField/tokenNormalDark@2x.png | Bin 0 -> 4341 bytes 10 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 JSTokenField/tokenHighlightedDark.png create mode 100644 JSTokenField/tokenHighlightedDark@2x.png create mode 100644 JSTokenField/tokenNormalDark.png create mode 100644 JSTokenField/tokenNormalDark@2x.png diff --git a/JSTokenField.xcodeproj/project.pbxproj b/JSTokenField.xcodeproj/project.pbxproj index 23652b8..2fff879 100644 --- a/JSTokenField.xcodeproj/project.pbxproj +++ b/JSTokenField.xcodeproj/project.pbxproj @@ -23,6 +23,10 @@ 1A1A06C413FEE2D900CA6645 /* tokenNormal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1A1A06C013FEE2D900CA6645 /* tokenNormal@2x.png */; }; 1A1A06CF13FF000C00CA6645 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A1A06CD13FF000C00CA6645 /* AddressBook.framework */; }; 1A1A06D013FF000C00CA6645 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A1A06CE13FF000C00CA6645 /* AddressBookUI.framework */; }; + 8223ECC516672B0100221221 /* tokenHighlightedDark.png in Resources */ = {isa = PBXBuildFile; fileRef = 8223ECC116672B0100221221 /* tokenHighlightedDark.png */; }; + 8223ECC616672B0100221221 /* tokenHighlightedDark@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8223ECC216672B0100221221 /* tokenHighlightedDark@2x.png */; }; + 8223ECC716672B0100221221 /* tokenNormalDark.png in Resources */ = {isa = PBXBuildFile; fileRef = 8223ECC316672B0100221221 /* tokenNormalDark.png */; }; + 8223ECC816672B0100221221 /* tokenNormalDark@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8223ECC416672B0100221221 /* tokenNormalDark@2x.png */; }; B71650D1144399F800EBF2C7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A1A069C13FEDEEC00CA6645 /* Foundation.framework */; }; B71650DB14439A0500EBF2C7 /* JSTokenField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A1A06B913FEE01C00CA6645 /* JSTokenField.h */; }; B71650DC14439A0500EBF2C7 /* JSTokenField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A06BA13FEE01C00CA6645 /* JSTokenField.m */; }; @@ -54,6 +58,10 @@ 1A1A06C013FEE2D900CA6645 /* tokenNormal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tokenNormal@2x.png"; sourceTree = ""; }; 1A1A06CD13FF000C00CA6645 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; 1A1A06CE13FF000C00CA6645 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; + 8223ECC116672B0100221221 /* tokenHighlightedDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tokenHighlightedDark.png; sourceTree = ""; }; + 8223ECC216672B0100221221 /* tokenHighlightedDark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tokenHighlightedDark@2x.png"; sourceTree = ""; }; + 8223ECC316672B0100221221 /* tokenNormalDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tokenNormalDark.png; sourceTree = ""; }; + 8223ECC416672B0100221221 /* tokenNormalDark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tokenNormalDark@2x.png"; sourceTree = ""; }; B71650D0144399F800EBF2C7 /* libJSTokenFieldLibrary.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJSTokenFieldLibrary.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -131,6 +139,10 @@ 1A1A06A113FEDEEC00CA6645 /* Supporting Files */ = { isa = PBXGroup; children = ( + 8223ECC116672B0100221221 /* tokenHighlightedDark.png */, + 8223ECC216672B0100221221 /* tokenHighlightedDark@2x.png */, + 8223ECC316672B0100221221 /* tokenNormalDark.png */, + 8223ECC416672B0100221221 /* tokenNormalDark@2x.png */, 1A1A06A213FEDEEC00CA6645 /* JSTokenField-Info.plist */, 1A1A06A313FEDEEC00CA6645 /* InfoPlist.strings */, 1A1A06A613FEDEEC00CA6645 /* main.m */, @@ -230,6 +242,10 @@ 1A1A06C213FEE2D900CA6645 /* tokenHighlighted@2x.png in Resources */, 1A1A06C313FEE2D900CA6645 /* tokenNormal.png in Resources */, 1A1A06C413FEE2D900CA6645 /* tokenNormal@2x.png in Resources */, + 8223ECC516672B0100221221 /* tokenHighlightedDark.png in Resources */, + 8223ECC616672B0100221221 /* tokenHighlightedDark@2x.png in Resources */, + 8223ECC716672B0100221221 /* tokenNormalDark.png in Resources */, + 8223ECC816672B0100221221 /* tokenNormalDark@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JSTokenField/DemoViewController.m b/JSTokenField/DemoViewController.m index 08cc9ac..6e61ee5 100644 --- a/JSTokenField/DemoViewController.m +++ b/JSTokenField/DemoViewController.m @@ -28,6 +28,7 @@ #import "DemoViewController.h" #import "JSTokenField.h" +#import "JSTokenButton.h" @implementation DemoViewController @@ -62,7 +63,13 @@ - (void)viewDidLoad [[_toField label] setText:@"To:"]; [_toField setDelegate:self]; [self.view addSubview:_toField]; - + + //Enable to change default button texture and title color + [JSTokenButton setDefaultHighlightedButtonImage:[[UIImage imageNamed:@"tokenHighlightedDark"] stretchableImageWithLeftCapWidth:14 topCapHeight:0]]; + [JSTokenButton setDefaultNormalButtonImage:[[UIImage imageNamed:@"tokenNormalDark"] stretchableImageWithLeftCapWidth:14 topCapHeight:0]]; + [JSTokenButton setDefaultNormalButtonTitleColor:[UIColor whiteColor]]; + [JSTokenButton setDefaultHighlightedButtonTitleColor:[UIColor blackColor]]; + UIView *separator1 = [[[UIView alloc] initWithFrame:CGRectMake(0, _toField.bounds.size.height-1, _toField.bounds.size.width, 1)] autorelease]; [separator1 setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin]; [_toField addSubview:separator1]; @@ -160,4 +167,11 @@ - (void)handleTokenFieldFrameDidChange:(NSNotification *)note } } +- (void)tokenField:(JSTokenField *)tokenField token:(JSTokenButton *)tokBtn toggledTo:(BOOL)toggleValue { + NSLog(@"Token %@ toggled to %d", tokBtn.representedObject, toggleValue); +} + +- (void)tokenField:(JSTokenField *)tokenField tokenTouchedUpInside:(JSTokenButton *)tokBtn { + NSLog(@"Token button %@ touched", tokBtn.representedObject); +} @end diff --git a/JSTokenField/JSTokenButton.h b/JSTokenField/JSTokenButton.h index 1223204..5cc675e 100644 --- a/JSTokenField/JSTokenButton.h +++ b/JSTokenField/JSTokenButton.h @@ -37,7 +37,6 @@ UIImage *_highlightedBg; id _representedObject; - } @property (nonatomic, getter=isToggled) BOOL toggled; @@ -48,7 +47,17 @@ @property (nonatomic, retain) id representedObject; @property (nonatomic, assign) JSTokenField *parentField; +@property (nonatomic, strong) UIColor *normalTitleColor; +@property (nonatomic, strong) UIColor *highlightedTitleColor; + + (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj; ++ (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj normalBG:(UIImage *)nbg highlightedBG:(UIImage *)hbg normalTitleColor:(UIColor *)normalTColor highlightedTitleColor:(UIColor *)hiTColor; + +//Customization related methods ++ (void)setDefaultNormalButtonImage:(UIImage *)image; ++ (void)setDefaultHighlightedButtonImage:(UIImage *)image; ++ (void)setDefaultNormalButtonTitleColor:(UIColor *)nColor; ++ (void)setDefaultHighlightedButtonTitleColor:(UIColor *)hColor; @end diff --git a/JSTokenField/JSTokenButton.m b/JSTokenField/JSTokenButton.m index f20112b..f00be37 100644 --- a/JSTokenField/JSTokenButton.m +++ b/JSTokenField/JSTokenButton.m @@ -38,13 +38,84 @@ @implementation JSTokenButton @synthesize representedObject = _representedObject; @synthesize parentField = _parentField; +/*- (id)init +{ + self = [super init]; + if (self) { + self.ty + } + return self; +}*/ + +static __strong UIImage *_defaultNormalButtonImage = nil; +static __strong UIImage *_defaultHighlightedButtonImage = nil; +static __strong UIColor *_defaultNormalButtonTitleColor = nil; +static __strong UIColor *_defaultHighlightedButtonTitleColor = nil; + + (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj { + return [JSTokenButton tokenWithString:string + representedObject:obj + normalBG:nil + highlightedBG:nil + normalTitleColor:nil + highlightedTitleColor:nil + ]; +} + ++ (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj normalBG:(UIImage *)nbg highlightedBG:(UIImage *)hbg normalTitleColor:(UIColor *)normalTColor highlightedTitleColor:(UIColor *)hiTColor { JSTokenButton *button = (JSTokenButton *)[self buttonWithType:UIButtonTypeCustom]; - [button setNormalBg:[[UIImage imageNamed:@"tokenNormal.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0]]; - [button setHighlightedBg:[[UIImage imageNamed:@"tokenHighlighted.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0]]; + if (nbg == nil) { + if (_defaultNormalButtonImage == nil) { + button.normalBg = [[UIImage imageNamed:@"tokenNormal"] + stretchableImageWithLeftCapWidth:14 + topCapHeight:0]; + } + else { + button.normalBg = _defaultNormalButtonImage; + } + } + else { + button.normalBg = nbg; + } + if (hbg == nil) { + if (_defaultHighlightedButtonImage == nil) { + button.highlightedBg = [[UIImage imageNamed:@"tokenHighlighted"] + stretchableImageWithLeftCapWidth:14 + topCapHeight:0]; + } + else { + button.highlightedBg = _defaultHighlightedButtonImage; + } + } + else { + button.highlightedBg = hbg; + } [button setAdjustsImageWhenHighlighted:NO]; - [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + if (normalTColor == nil) { + if (_defaultNormalButtonTitleColor == nil) { + button.normalTitleColor = [UIColor blackColor]; + } + else { + button.normalTitleColor = _defaultNormalButtonTitleColor; + } + } + else { + button.normalTitleColor = normalTColor; + } + if (hiTColor == nil) { + if (_defaultHighlightedButtonTitleColor == nil) { + button.highlightedTitleColor = [UIColor whiteColor]; + } + else { + button.highlightedTitleColor = _defaultHighlightedButtonTitleColor; + } + } + else { + button.highlightedTitleColor = hiTColor; + } + [button setTitleColor:button.normalTitleColor forState:UIControlStateNormal]; + [[button titleLabel] setFont:[UIFont fontWithName:@"Helvetica Neue" size:15]]; [[button titleLabel] setLineBreakMode:UILineBreakModeTailTruncation]; [button setTitleEdgeInsets:UIEdgeInsetsMake(2, 10, 0, 10)]; @@ -61,7 +132,7 @@ + (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj [button setRepresentedObject:obj]; - return button; + return button; } - (void)setToggled:(BOOL)toggled @@ -71,12 +142,12 @@ - (void)setToggled:(BOOL)toggled if (_toggled) { [self setBackgroundImage:self.highlightedBg forState:UIControlStateNormal]; - [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self setTitleColor:self.highlightedTitleColor forState:UIControlStateNormal]; } else { [self setBackgroundImage:self.normalBg forState:UIControlStateNormal]; - [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self setTitleColor:self.normalTitleColor forState:UIControlStateNormal]; } } @@ -121,4 +192,21 @@ - (BOOL)canBecomeFirstResponder { return YES; } +#pragma mark - Customization related methods + ++ (void)setDefaultNormalButtonImage:(UIImage *)image { + _defaultNormalButtonImage = [image copy]; +} + ++ (void)setDefaultHighlightedButtonImage:(UIImage *)image { + _defaultHighlightedButtonImage = [image copy]; +} + ++ (void)setDefaultNormalButtonTitleColor:(UIColor *)nColor { + _defaultNormalButtonTitleColor = [nColor copy]; +} + ++ (void)setDefaultHighlightedButtonTitleColor:(UIColor *)hColor { + _defaultHighlightedButtonTitleColor = [hColor copy]; +} @end diff --git a/JSTokenField/JSTokenField.h b/JSTokenField/JSTokenField.h index 415ef05..5438d8e 100644 --- a/JSTokenField/JSTokenField.h +++ b/JSTokenField/JSTokenField.h @@ -58,6 +58,11 @@ extern NSString *const JSDeletedTokenKey; - (void)removeTokenForString:(NSString *)string; - (void)removeTokenWithRepresentedObject:(id)representedObject; +- (void)setNormalButtonImage:(UIImage *)image; +- (void)setHighlightedButtonImage:(UIImage *)image; +- (void)setNormalButtonTitleColor:(UIColor *)nColor; +- (void)setHighlightedButtonTitleColor:(UIColor *)hColor; + @end @protocol JSTokenFieldDelegate @@ -70,4 +75,6 @@ extern NSString *const JSDeletedTokenKey; - (BOOL)tokenFieldShouldReturn:(JSTokenField *)tokenField; - (void)tokenFieldDidEndEditing:(JSTokenField *)tokenField; +- (void)tokenField:(JSTokenField *)tokenField token:(JSTokenButton *)tokBtn toggledTo:(BOOL)toggleValue; +- (void)tokenField:(JSTokenField *)tokenField tokenTouchedUpInside:(JSTokenButton *)tokBtn; @end diff --git a/JSTokenField/JSTokenField.m b/JSTokenField/JSTokenField.m index 4bd5907..6b17809 100644 --- a/JSTokenField/JSTokenField.m +++ b/JSTokenField/JSTokenField.m @@ -48,6 +48,11 @@ - (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj; - (void)deleteHighlightedToken; - (void)commonSetup; + +@property (nonatomic, strong) UIImage *buttonNormalImage; +@property (nonatomic, strong) UIImage *buttonHightlightedImage; +@property (nonatomic, strong) UIColor *buttonNormalTitleColor; +@property (nonatomic, strong) UIColor *buttonHighlightedTitleColor; @end @@ -117,6 +122,10 @@ - (void)commonSetup { selector:@selector(handleTextDidChange:) name:UITextFieldTextDidChangeNotification object:_textField]; + + //Initialize JSTokenButton background images to nil so the default background images are used by default + _buttonHightlightedImage = nil; + _buttonNormalImage = nil; } - (void)dealloc @@ -146,7 +155,6 @@ - (void)addTokenWithTitle:(NSString *)string representedObject:(id)obj { [self.delegate tokenField:self didAddToken:aString representedObject:obj]; } - [self setNeedsLayout]; } } @@ -215,7 +223,12 @@ - (void)deleteHighlightedToken - (JSTokenButton *)tokenWithString:(NSString *)string representedObject:(id)obj { - JSTokenButton *token = [JSTokenButton tokenWithString:string representedObject:obj]; + JSTokenButton *token = [JSTokenButton tokenWithString:string representedObject:obj + normalBG:self.buttonNormalImage + highlightedBG:self.buttonHightlightedImage + normalTitleColor:self.buttonNormalTitleColor + highlightedTitleColor:self.buttonHighlightedTitleColor]; + CGRect frame = [token frame]; if (frame.size.width > self.frame.size.width) @@ -295,12 +308,24 @@ - (void)toggle:(id)sender { for (JSTokenButton *token in _tokens) { - [token setToggled:NO]; + if (token != (JSTokenButton *)sender) { + [token setToggled:NO]; + if ([self.delegate respondsToSelector:@selector(tokenField:token:toggledTo:)]) { + [self.delegate tokenField:self token:token toggledTo:NO]; + } + } + else { + BOOL toggleValue = (token.isToggled)?NO:YES; + [token setToggled:toggleValue]; + [token becomeFirstResponder]; + if ([self.delegate respondsToSelector:@selector(tokenField:tokenTouchedUpInside:)]) { + [self.delegate tokenField:self tokenTouchedUpInside:token]; + } + if ([self.delegate respondsToSelector:@selector(tokenField:token:toggledTo:)]) { + [self.delegate tokenField:self token:token toggledTo:toggleValue]; + } + } } - - JSTokenButton *token = (JSTokenButton *)sender; - [token setToggled:YES]; - [token becomeFirstResponder]; } - (void)setFrame:(CGRect)frame @@ -322,6 +347,44 @@ - (void)setFrame:(CGRect)frame } } +#pragma mark - +#pragma mark JSTokenButton customization methods +- (void)setNormalButtonImage:(UIImage *)image { + if (image != nil) { + self.buttonNormalImage = image; + for (JSTokenButton *token in _tokens) { + [token setNormalBg:self.buttonNormalImage]; + } + } +} + +- (void)setHighlightedButtonImage:(UIImage *)image { + if (image != nil) { + self.buttonHightlightedImage = image; + for (JSTokenButton *token in _tokens) { + [token setHighlightedBg:self.buttonHightlightedImage]; + } + } +} + +- (void)setNormalButtonTitleColor:(UIColor *)nColor { + if (nColor != nil) { + self.buttonNormalTitleColor = nColor; + for (JSTokenButton *token in _tokens) { + token.normalTitleColor = self.buttonNormalTitleColor; + } + } +} + +- (void)setHighlightedButtonTitleColor:(UIColor *)hColor { + if (hColor != nil) { + self.buttonHighlightedTitleColor = hColor; + for (JSTokenButton *token in _tokens) { + token.highlightedTitleColor = self.buttonHighlightedTitleColor; + } + } +} + #pragma mark - #pragma mark UITextFieldDelegate diff --git a/JSTokenField/tokenHighlightedDark.png b/JSTokenField/tokenHighlightedDark.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4c46ac513b7922b35651100db7778317029a9c GIT binary patch literal 3584 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 literal 0 HcmV?d00001 diff --git a/JSTokenField/tokenNormalDark@2x.png b/JSTokenField/tokenNormalDark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d92e53d39e3d931b9de4e310d40f9b7ee98e979b GIT binary patch literal 4341 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 literal 0 HcmV?d00001