-
-
Save w-i-n-s/8340df38da7d3e1144ff7e26a475c678 to your computer and use it in GitHub Desktop.
obj-c/iOS keyboard extension - long press / press and hold
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
*/code edited by me but originally it is not mine/* | |
NSString* const rowComponentSeparator = @" "; | |
//using with standart localization | |
... | |
NSString *keys = NSLocalizedStringFromTable(@"letterPad3", kLocalizedTableSymbols, @"Q W E R T Y U I P by default"); | |
NSArray *letters = [row componentsSeparatedByString:rowComponentSeparator]; | |
ACKey *key; | |
for (NSString *letter in letters) { | |
key = [ACKey keyWithTitle:letter]; | |
} | |
//after fill buttons | |
[self checkHintPositionForKeysList:buttons]; | |
... | |
//check every button for hint | |
- (void)checkHintPositionForKeysList:(NSArray*)keysList { | |
NSUInteger counter = 0, halfListCount = round([keysList count]/2); | |
NSString *hintsList = NSLocalizedStringFromTable(@"hintsList", kLocalizedTableSymbols, @"±hints strings list"); | |
NSArray *array = [hintsList componentsSeparatedByString:@","]; | |
NSMutableArray *driveSymbols = [NSMutableArray array]; | |
NSMutableDictionary *hints = [NSMutableDictionary dictionary]; | |
NSString *currentSymbol; | |
for (NSString *hintRow in array) { | |
currentSymbol = [hintRow substringToIndex:1]; | |
[driveSymbols addObject:currentSymbol]; | |
[hints setObject:hintRow forKey:currentSymbol]; | |
} | |
for (ACKey *key in keysList) { | |
if ([driveSymbols containsObject: key.title]) { | |
key.hintSymbolsList = [((NSString*)[hints objectForKey:key.title]) componentsSeparatedByString:rowComponentSeparator]; | |
} | |
//because from left to right in one row | |
if (counter >= halfListCount) { | |
key.hintPosition = ACHintPositionRight; | |
} else { | |
key.hintPosition = ACHintPositionLeft; | |
} | |
counter++; | |
} | |
if ([keysList count] > 9) { | |
((ACKey*)[keysList firstObject]).hintPosition = ACHintPositionFarLeft; | |
((ACKey*)[keysList lastObject]).hintPosition = ACHintPositionFarRight; | |
} | |
} | |
//LocalizedTableSymbols.strings (Spainish) | |
/* title for return button */ | |
"returnTitleSearch" = "Search"; | |
/* ±hints strings list */ | |
"hintsList" = "A À Á Â Ä Æ Ã Å Ā,C Ç Ć Č,E È É Ê Ë Ē Ė Ę,I Î Ï Í Ī Į Ì,L Ł,N Ñ Ń,O Ô Ö Ò Ó Œ Ø Ō Õ,S Ś Š,U Û Ü Ù Ú Ū,Y Ÿ,Z Ž Ź Ż"; | |
//LocalizedTableSymbols.strings (French) | |
/* title for return button */ | |
"returnTitleSearch" = "Rechercher"; | |
/* ±hints strings list */ | |
"hintsList" = "E É,' ` ˆ ¨ ´,\" » « ” “ „,A À  ª Æ Á Ä Ã Å Ā,C Ç Ć Č,E É È Ê Ë Ę Ė Ē,I Î Ï Ì Í Į Ī,N Ñ Ń,O Ô Œ º Ö Ò Ó Õ Ø Ō,U Û Ù Ü Ú Ū,Y Ÿ"; | |
//ACKey.h | |
#import <UIKit/UIKit.h> | |
typedef NS_ENUM(NSUInteger, ACHintPosition) { | |
ACHintPositionFarLeft, | |
ACHintPositionLeft, | |
ACHintPositionRight, | |
ACHintPositionFarRight | |
}; | |
@interface ACKey : UIControl | |
/** The position for long-tap hint - for "a" ACHintPositionFarLeft | |
*/ | |
@property (nonatomic, assign) ACHintPosition hintPosition; | |
/** List of strings for showing in hint popup | |
*/ | |
@property (nonatomic, strong) NSArray *hintSymbolsList; | |
@end | |
//ACKey.m | |
#import "ACKey.h" | |
#define ACKEY_OVERLAY_KEY -12 | |
@interface ACKey () | |
@property (nonatomic, weak) NSTimer *hidePopupTimer; | |
@property (nonatomic, weak) NSTimer *showHintTimer; | |
@property (nonatomic, strong) UIView *hintView; | |
@property (nonatomic, assign) CGFloat hintAdditionalWidth; | |
@property (nonatomic, strong) NSArray *hintButtons; | |
@end | |
#define __FAR_SHIFT (12 * [[UIScreen mainScreen] scale]) | |
#define __UPPER_WIDTH (55.0 * [[UIScreen mainScreen] scale]) | |
#define __LOWER_WIDTH (self.frame.size.width * [[UIScreen mainScreen] scale]) | |
#define __PAN_UPPER_RADIUS (10.0 * [[UIScreen mainScreen] scale]) | |
#define __PAN_LOWER_RADIUS (5.0 * [[UIScreen mainScreen] scale]) | |
#define __PAN_UPPDER_WIDTH (__UPPER_WIDTH-__PAN_UPPER_RADIUS*2) | |
#define __PAN_UPPER_HEIGHT (56.0 * [[UIScreen mainScreen] scale]) | |
#define __PAN_LOWER_WIDTH (__LOWER_WIDTH-__PAN_LOWER_RADIUS*2) | |
#define __PAN_LOWER_HEIGHT (47.0 * [[UIScreen mainScreen] scale]) | |
#define __PAN_UL_WIDTH ((__UPPER_WIDTH-__LOWER_WIDTH)/2) | |
#define __PAN_MIDDLE_HEIGHT (2.0 * [[UIScreen mainScreen] scale]) | |
#define __PAN_CURVE_SIZE (10.0 * [[UIScreen mainScreen] scale]) | |
#define __PADDING_X (15 * [[UIScreen mainScreen] scale]) | |
#define __PADDING_Y (10 * [[UIScreen mainScreen] scale]) | |
#define __WIDTH (__UPPER_WIDTH + __PADDING_X*2) | |
#define __HEIGHT (__PAN_UPPER_HEIGHT + __PAN_MIDDLE_HEIGHT + __PAN_LOWER_HEIGHT + __PADDING_Y*2) | |
#define __OFFSET_X (-25 * [[UIScreen mainScreen] scale]) | |
#define __OFFSET_Y (59 * [[UIScreen mainScreen] scale]) | |
#define __GAP_X (3 * [[UIScreen mainScreen] scale]) | |
@implementation ACKey | |
- (void)addPopupToButton:(ACKey *)b { | |
[self hidePopup]; | |
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationHideButtonPopup | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(hidePopup) | |
name:kNotificationHideButtonPopup | |
object:nil]; | |
if (b.title.length && b.title.length == 1){ | |
UIImageView *keyPop = nil; | |
if (self.appearance == ACKeyAppearanceClearWhite) { | |
keyPop = [[UIImageView alloc] initWithFrame:CGRectMake(-3, | |
-4.5, | |
self.frame.size.width+6, | |
self.frame.size.height+9)]; | |
keyPop.backgroundColor = [UIColor colorWithRed: 19/255.0 | |
green:160/255.0 | |
blue:237/255.0 | |
alpha:0.3]; | |
} else { | |
UIImage* image = [self keytopImage]; | |
keyPop = [[UIImageView alloc] initWithImage:image]; | |
keyPop.frame = CGRectMake((self.frame.size.width - image.size.width) / 2, | |
-71, | |
keyPop.frame.size.width, | |
keyPop.frame.size.height); | |
UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, keyPop.frame.size.width, 60)]; | |
[text setFont:[UIFont systemFontOfSize:35]]; | |
[text setTextAlignment:NSTextAlignmentCenter]; | |
[text setBackgroundColor:[UIColor clearColor]]; | |
[text setAdjustsFontSizeToFitWidth:YES]; | |
[text setText:b.title]; | |
[text setTextColor:self.label.textColor]; | |
keyPop.layer.shadowColor = [UIColor colorWithWhite:0.1 alpha:1.0].CGColor; | |
keyPop.layer.shadowOffset = CGSizeMake(0, 2.0); | |
keyPop.layer.shadowOpacity = 0.30; | |
keyPop.layer.shadowRadius = 3.0; | |
keyPop.clipsToBounds = NO; | |
[keyPop addSubview:text]; | |
} | |
[keyPop setTag:ACKEY_POPUP_VIEV_TAG]; | |
[keyPop setAlpha:0.8]; | |
[b addSubview:keyPop]; | |
[UIView animateWithDuration:kKeyPopapAppearDuration | |
animations:^{ | |
[keyPop setAlpha:1.0]; | |
}]; | |
[self startShowHintTimer]; | |
} | |
} | |
- (void)addHintToOurSelf { | |
if (!self.hintSymbolsList || ![self.hintSymbolsList count]) { | |
return; | |
} | |
//TODO: fix selection button and -updateState after it when hint view was added | |
[self setHighlighted:NO]; | |
[self setSelected:NO]; | |
[self updateState]; | |
[self hidePopup]; | |
UIImage* image = [self hintImage]; | |
self.hintView = [[UIImageView alloc] initWithImage:image]; | |
BOOL isRightHint = self.hintPosition == ACHintPositionFarRight || self.hintPosition == ACHintPositionRight; | |
CGFloat xPos; | |
if (isRightHint) { | |
xPos = (self.frame.size.width - (image.size.width + self.hintAdditionalWidth/2))/2; | |
} else { //ACHintPositionLeft & ACHintPositionFarLeft | |
xPos = -27; | |
} | |
self.hintView.frame = CGRectMake(xPos, | |
-71, | |
self.hintView.frame.size.width, | |
self.hintView.frame.size.height); | |
self.hintView.layer.shadowColor = [UIColor colorWithWhite:0.1 alpha:1.0].CGColor; | |
self.hintView.layer.shadowOffset = CGSizeMake(0, 2.0); | |
self.hintView.layer.shadowOpacity = 0.30; | |
self.hintView.layer.shadowRadius = 3.0; | |
self.hintView.clipsToBounds = NO; | |
UIButton *button; | |
NSString *hint; | |
BOOL isLowCase = [self.title.lowercaseString isEqualToString:self.title]; | |
NSMutableArray *hintStrings = [NSMutableArray array]; | |
if (isRightHint) { | |
for (int i = (int)[self.hintSymbolsList count]-1; i >= 0; i--) { | |
[hintStrings addObject:self.hintSymbolsList[i]]; | |
} | |
}else{ | |
[hintStrings addObjectsFromArray: self.hintSymbolsList]; | |
} | |
NSMutableArray *mArray = [NSMutableArray array]; | |
for (int i=0; i<[self.hintSymbolsList count]; i++) { | |
hint = [hintStrings objectAtIndex:i]; | |
button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
button.frame = CGRectMake(__PAN_UL_WIDTH+i*(self.frame.size.width+__GAP_X)+(isRightHint?0:__GAP_X-1), | |
20, | |
self.frame.size.width, | |
self.frame.size.height); | |
[button setTitle:(isLowCase ? hint.lowercaseString:hint) forState:UIControlStateNormal]; | |
[button.titleLabel setFont:[UIFont systemFontOfSize:kKeyPhoneTitleFontSize+(isLowCase ? 2:0)]]; | |
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; | |
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
[button setBackgroundImage:[UIImage imageNamed:@"hint_button_back"] forState:UIControlStateHighlighted]; | |
[self.hintView addSubview:button]; | |
[mArray addObject:button]; | |
} | |
if (isRightHint) { | |
[mArray.lastObject setHighlighted:YES]; | |
} else { | |
[mArray.firstObject setHighlighted:YES]; | |
} | |
self.hintButtons = mArray; | |
self.hintView.layer.shadowColor = [UIColor colorWithWhite:0.1 alpha:1.0].CGColor; | |
self.hintView.layer.shadowOffset = CGSizeMake(0, 2.0); | |
self.hintView.layer.shadowOpacity = 0.40; | |
self.hintView.layer.shadowRadius = 3.0; | |
self.hintView.clipsToBounds = NO; | |
[self addSubview:self.hintView]; | |
/* | |
UIImage* image = [self keytopImage]; | |
keyPop = [[UIImageView alloc] initWithImage:image]; | |
keyPop.frame = CGRectMake((self.frame.size.width - image.size.width) / 2, | |
-71, | |
keyPop.frame.size.width, | |
keyPop.frame.size.height); | |
CGFloat shift = 0; | |
CGFloat amount = self.frame.size.width/3; | |
if (self.hintPosition == ACHintPositionFarLeft) { | |
shift = amount; | |
}else if (self.hintPosition == ACHintPositionFarRight) { | |
shift = -amount; | |
} | |
UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(shift, 10, keyPop.frame.size.width, 60)]; | |
[text setFont:[UIFont systemFontOfSize:35]]; | |
[text setTextAlignment:NSTextAlignmentCenter]; | |
[text setBackgroundColor:[UIColor clearColor]]; | |
[text setAdjustsFontSizeToFitWidth:YES]; | |
[text setText:b.title]; | |
[text setTextColor:self.label.textColor]; | |
*/ | |
} | |
// scheme | |
/* | |
1 2 | |
_______> 3 | |
13 / \ | |
| | | |
12 | | 4 | |
\ / | |
11 \ / 5 | |
10| | | |
| | 6 | |
9 \<---/ 7 | |
8 | |
1 2 | |
_______>_______ 3 | |
13 / \ | |
| | | |
12 | | 4 | |
\ 5.2 _______/5.1 | |
11 \ / 5.3 | |
10| | | |
| | 6 | |
9 \<---/ 7 | |
8 | |
*/ | |
- (UIImage *)keytopImage { | |
CGMutablePathRef path = CGPathCreateMutable(); | |
CGPoint p = CGPointMake(__PADDING_X, __PADDING_Y); | |
CGPoint p1 = CGPointZero; | |
CGPoint p2 = CGPointZero; | |
//1 | |
p.x += __PAN_UPPER_RADIUS; | |
CGPathMoveToPoint(path, NULL, p.x, p.y); | |
//2 | |
p.x += __PAN_UPPDER_WIDTH; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//3 | |
p.y += __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
3.0*M_PI/2.0, | |
4.0*M_PI/2.0, | |
false); | |
//4 | |
p.x += __PAN_UPPER_RADIUS; | |
p.y += __PAN_UPPER_HEIGHT - __PAN_UPPER_RADIUS - __PAN_CURVE_SIZE; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//5 | |
p1 = CGPointMake(p.x, p.y + __PAN_CURVE_SIZE); | |
switch (self.hintPosition) { | |
case ACHintPositionFarRight: | |
p.x -= __PAN_UL_WIDTH*2; | |
break; | |
case ACHintPositionLeft: | |
case ACHintPositionRight: | |
p.x -= __PAN_UL_WIDTH; | |
break; | |
case ACHintPositionFarLeft: | |
break; | |
} | |
p.y += __PAN_MIDDLE_HEIGHT + __PAN_CURVE_SIZE*2; | |
p2 = CGPointMake(p.x, p.y - __PAN_CURVE_SIZE); | |
CGPathAddCurveToPoint(path, NULL, | |
p1.x, p1.y, | |
p2.x, p2.y, | |
p.x, p.y); | |
//6 | |
p.y += __PAN_LOWER_HEIGHT - __PAN_CURVE_SIZE - __PAN_LOWER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//7 | |
p.x -= __PAN_LOWER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_LOWER_RADIUS, | |
4.0*M_PI/2.0, | |
1.0*M_PI/2.0, | |
false); | |
//8 | |
p.x -= __PAN_LOWER_WIDTH; | |
p.y += __PAN_LOWER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//9 | |
p.y -= __PAN_LOWER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_LOWER_RADIUS, | |
1.0*M_PI/2.0, | |
2.0*M_PI/2.0, | |
false); | |
//10 | |
p.x -= __PAN_LOWER_RADIUS; | |
p.y -= __PAN_LOWER_HEIGHT - __PAN_LOWER_RADIUS - __PAN_CURVE_SIZE; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//11 | |
p1 = CGPointMake(p.x, p.y - __PAN_CURVE_SIZE); | |
switch (self.hintPosition) { | |
case ACHintPositionFarRight: | |
break; | |
case ACHintPositionLeft: | |
case ACHintPositionRight: | |
p.x -= __PAN_UL_WIDTH; | |
break; | |
case ACHintPositionFarLeft: | |
p.x -= __PAN_UL_WIDTH*2; | |
break; | |
} | |
p.y -= __PAN_MIDDLE_HEIGHT + __PAN_CURVE_SIZE*2; | |
p2 = CGPointMake(p.x, p.y + __PAN_CURVE_SIZE); | |
CGPathAddCurveToPoint(path, NULL, | |
p1.x, p1.y, | |
p2.x, p2.y, | |
p.x, p.y); | |
//12 | |
p.y -= __PAN_UPPER_HEIGHT - __PAN_UPPER_RADIUS - __PAN_CURVE_SIZE; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//13 | |
p.x += __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
2.0*M_PI/2.0, | |
3.0*M_PI/2.0, | |
false); | |
//---- | |
CGContextRef context; | |
UIGraphicsBeginImageContext(CGSizeMake(__WIDTH, | |
__HEIGHT)); | |
context = UIGraphicsGetCurrentContext(); | |
switch (self.hintPosition) { | |
case ACHintPositionFarRight: | |
CGContextTranslateCTM(context, __FAR_SHIFT, __HEIGHT); | |
break; | |
case ACHintPositionLeft: | |
case ACHintPositionRight: | |
CGContextTranslateCTM(context, 0.0, __HEIGHT); | |
break; | |
case ACHintPositionFarLeft: | |
CGContextTranslateCTM(context, (-1)*__FAR_SHIFT, __HEIGHT); | |
break; | |
} | |
CGContextScaleCTM(context, 1.0, -1.0); | |
CGContextAddPath(context, path); | |
CGContextClip(context); | |
//---- | |
CGRect frame = CGPathGetBoundingBox(path); | |
CGColorRef backColor; | |
switch (self.appearance) { | |
case ACKeyAppearanceDark: | |
backColor = [ACDarkAppearance lightKeyColor].CGColor; | |
break; | |
case ACKeyAppearanceLight: | |
backColor = [ACLightAppearance lightKeyColor].CGColor; | |
break; | |
default: | |
break; | |
} | |
CGContextSetFillColorWithColor(context, backColor); | |
CGContextFillRect(context, frame); | |
CGImageRef imageRef = CGBitmapContextCreateImage(context); | |
UIImage * image = [UIImage imageWithCGImage:imageRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationDown]; | |
CGImageRelease(imageRef); | |
UIGraphicsEndImageContext(); | |
CFRelease(path); | |
return image; | |
} | |
- (UIImage*)hintImage { | |
CGMutablePathRef path = CGPathCreateMutable(); | |
CGPoint p = CGPointMake(__PADDING_X, __PADDING_Y); | |
CGPoint p1 = CGPointZero; | |
CGPoint p2 = CGPointZero; | |
//1 | |
p.x += __PAN_UPPER_RADIUS; | |
CGPathMoveToPoint(path, NULL, p.x, p.y); | |
NSUInteger hintCount = [self.hintSymbolsList count]; | |
//!!!:magic numbers | |
self.hintAdditionalWidth = 2*(hintCount-1)*(self.frame.size.width+__GAP_X); | |
//2 | |
p.x += __PAN_UPPDER_WIDTH + self.hintAdditionalWidth; | |
//!!!:+hintCount*(__PAN_LOWER_WIDTH+__GAP_X); | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//3 | |
p.y += __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
3.0*M_PI/2.0, | |
4.0*M_PI/2.0, | |
false); | |
p.x += __PAN_UPPER_RADIUS; | |
//4 | |
p.y += __PAN_UPPER_HEIGHT - __PAN_UPPER_RADIUS; | |
if (self.hintPosition == ACHintPositionFarRight || | |
self.hintPosition == ACHintPositionRight) { | |
p.y += - 2*__PAN_UPPER_RADIUS + __PAN_CURVE_SIZE + __PAN_MIDDLE_HEIGHT; | |
} else { //ACHintPositionLeft & ACHintPositionFarLeft | |
p.y -= __PAN_CURVE_SIZE; | |
} | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
if (self.hintPosition == ACHintPositionFarRight || | |
self.hintPosition == ACHintPositionRight) { | |
//5.1 | |
p.x -= __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
4.0*M_PI/2.0, | |
1.0*M_PI/2.0, | |
false); | |
p.y += __PAN_UPPER_RADIUS; | |
//5.2 | |
p.x -= self.hintAdditionalWidth + __PAN_UL_WIDTH-2*__PAN_UPPER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//5.3 | |
p.y += __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
3.0*M_PI/2.0, | |
2.0*M_PI/2.0, | |
true); | |
p.x -= __PAN_UPPER_RADIUS; | |
} else { //ACHintPositionLeft & ACHintPositionFarLeft | |
//5 | |
p1 = CGPointMake(p.x, p.y + __PAN_CURVE_SIZE); | |
p.x -= __PAN_UL_WIDTH; | |
p.y += __PAN_MIDDLE_HEIGHT + __PAN_CURVE_SIZE*2; | |
p2 = CGPointMake(p.x, p.y - __PAN_CURVE_SIZE); | |
CGPathAddCurveToPoint(path, NULL, | |
p1.x, p1.y, | |
p2.x, p2.y, | |
p.x, p.y); | |
} | |
//6 | |
p.y += __PAN_LOWER_HEIGHT - __PAN_CURVE_SIZE - __PAN_LOWER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//7 | |
p.x -= __PAN_LOWER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_LOWER_RADIUS, | |
4.0*M_PI/2.0, | |
1.0*M_PI/2.0, | |
false); | |
//8 | |
p.x -= __PAN_LOWER_WIDTH; | |
p.y += __PAN_LOWER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//9 | |
p.y -= __PAN_LOWER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_LOWER_RADIUS, | |
1.0*M_PI/2.0, | |
2.0*M_PI/2.0, | |
false); | |
//10 | |
p.x -= __PAN_LOWER_RADIUS; | |
p.y -= __PAN_LOWER_HEIGHT - __PAN_LOWER_RADIUS - __PAN_CURVE_SIZE; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
if (self.hintPosition == ACHintPositionFarRight || | |
self.hintPosition == ACHintPositionRight) { | |
//11 | |
p1 = CGPointMake(p.x, p.y - __PAN_CURVE_SIZE); | |
p.x -= __PAN_UL_WIDTH; | |
p.y -= __PAN_MIDDLE_HEIGHT + __PAN_CURVE_SIZE*2; | |
p2 = CGPointMake(p.x, p.y + __PAN_CURVE_SIZE); | |
CGPathAddCurveToPoint(path, NULL, | |
p1.x, p1.y, | |
p2.x, p2.y, | |
p.x, p.y); | |
} else { //ACHintPositionLeft & ACHintPositionFarLeft | |
//11.1 | |
p.x -= __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
4.0*M_PI/2.0, | |
3.0*M_PI/2.0, | |
true); | |
p.y -= __PAN_UPPER_RADIUS; | |
//11.2 | |
p.x -= self.hintAdditionalWidth + __PAN_UL_WIDTH-2*__PAN_UPPER_RADIUS; | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//11.3 | |
p.y -= __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
1.0*M_PI/2.0, | |
2.0*M_PI/2.0, | |
false); | |
p.x -= __PAN_UPPER_RADIUS; | |
} | |
//12 | |
p.y -= __PAN_UPPER_HEIGHT - __PAN_UPPER_RADIUS; | |
if (self.hintPosition == ACHintPositionFarRight || | |
self.hintPosition == ACHintPositionRight) { | |
p.y += __PAN_CURVE_SIZE; | |
} else { | |
p.y -= - 2*__PAN_UPPER_RADIUS + __PAN_CURVE_SIZE + __PAN_MIDDLE_HEIGHT; | |
} | |
CGPathAddLineToPoint(path, NULL, p.x, p.y); | |
//13 | |
p.x += __PAN_UPPER_RADIUS; | |
CGPathAddArc(path, NULL, | |
p.x, p.y, | |
__PAN_UPPER_RADIUS, | |
2.0*M_PI/2.0, | |
3.0*M_PI/2.0, | |
false); | |
//---- | |
CGContextRef context; | |
UIGraphicsBeginImageContext(CGSizeMake(__WIDTH+self.hintAdditionalWidth, | |
__HEIGHT)); | |
context = UIGraphicsGetCurrentContext(); | |
CGContextTranslateCTM(context, 0.0, __HEIGHT); | |
CGContextScaleCTM(context, 1.0, -1.0); | |
CGContextAddPath(context, path); | |
CGContextClip(context); | |
//---- | |
CGRect frame = CGPathGetBoundingBox(path); | |
CGColorRef backColor; | |
switch (self.appearance) { | |
case ACKeyAppearanceDark: | |
backColor = [ACDarkAppearance lightKeyColor].CGColor; | |
break; | |
case ACKeyAppearanceLight: | |
backColor = [ACLightAppearance lightKeyColor].CGColor; | |
break; | |
default: | |
break; | |
} | |
CGContextSetFillColorWithColor(context, backColor); | |
CGContextFillRect(context, frame); | |
CGImageRef imageRef = CGBitmapContextCreateImage(context); | |
UIImage * image = [UIImage imageWithCGImage:imageRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationDown]; | |
CGImageRelease(imageRef); | |
UIGraphicsEndImageContext(); | |
CFRelease(path); | |
return image; | |
} | |
#pragma mark - Touch handling | |
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { | |
[super touchesBegan:touches withEvent:event]; | |
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) [self addPopupToButton:self]; | |
[self updateState]; | |
// NSLog(@"T begin"); | |
} | |
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { | |
[super touchesMoved:touches withEvent:event]; | |
if (self.hintView) { | |
UITouch *firstTouch = [touches anyObject]; | |
BOOL leftHand = self.hintPosition == ACHintPositionLeft || self.hintPosition == ACHintPositionFarLeft; | |
CGFloat touchX = [firstTouch locationInView:self.superview].x + (leftHand ?self.frame.size.width - self.frame.origin.x:self.hintView.frame.size.width-self.frame.origin.x-2*self.frame.size.width); | |
UIButton *rightButton = self.hintButtons.lastObject, *leftButton = self.hintButtons.firstObject; | |
NSArray *array = [self.hintButtons filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) { | |
return ((UIButton*)evaluatedObject).center.x < touchX; | |
}]]; | |
if ([array count]) { | |
leftButton = array.lastObject; | |
} | |
array = [self.hintButtons filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) { | |
return ((UIButton*)evaluatedObject).center.x > touchX; | |
}]]; | |
if ([array count]) { | |
rightButton = array.firstObject; | |
} | |
for (UIButton* button in self.hintButtons) { | |
button.highlighted = NO; | |
} | |
//NSLog(@"L %f | %f | %f R",leftButton.center.x, touchX, rightButton.center.x); | |
if ((touchX - leftButton.center.x) < (rightButton.center.x - touchX)) { | |
[leftButton setHighlighted:YES]; | |
} else { | |
[rightButton setHighlighted:YES]; | |
} | |
} | |
[self updateState]; | |
// NSLog(@"T move"); | |
} | |
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { | |
if (self.hintButtons) { | |
[self setHighlighted:NO]; | |
NSArray *array = [self.hintButtons filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) { | |
return ((UIButton*)evaluatedObject).highlighted; | |
}]]; | |
if ([array count]) { | |
UIButton* highlightedButton = array.firstObject; | |
if (highlightedButton) { | |
//!!!: please refactor it | |
[((KeyboardView*)self.superview) insertHintText:highlightedButton.titleLabel.text]; | |
} | |
} | |
[self hideHintView]; | |
} else { | |
[super touchesEnded:touches withEvent:event]; | |
} | |
[self startHideTimerPopup]; | |
[self updateState]; | |
// NSLog(@"T end"); | |
} | |
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { | |
[super touchesCancelled:touches withEvent:event]; | |
[self startHideTimerPopup]; | |
[self updateState]; | |
// NSLog(@"T cancel"); | |
} | |
- (void)startHideTimerPopup{ | |
[self stopHideTimerPopup]; | |
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad){ | |
_hidePopupTimer = [NSTimer scheduledTimerWithTimeInterval:kKeyPopapStayAliveInterval | |
target:self | |
selector:@selector(hidePopup) | |
userInfo:nil | |
repeats:NO]; | |
} | |
} | |
- (void)hidePopup{ | |
[self stopShowHintTimer]; | |
[[NSNotificationCenter defaultCenter] removeObserver:self | |
name:kNotificationHideButtonPopup | |
object:nil]; | |
[self stopHideTimerPopup]; | |
[[self viewWithTag:ACKEY_POPUP_VIEV_TAG] removeFromSuperview]; | |
} | |
- (void)stopHideTimerPopup{ | |
[self.hidePopupTimer invalidate]; | |
_hidePopupTimer = nil; | |
} | |
- (void)startShowHintTimer { | |
[self stopShowHintTimer]; | |
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad){ | |
_showHintTimer = [NSTimer scheduledTimerWithTimeInterval:0.7 | |
target:self | |
selector:@selector(addHintToOurSelf) | |
userInfo:nil | |
repeats:NO]; | |
} | |
} | |
- (void)stopShowHintTimer { | |
[self.showHintTimer invalidate]; | |
_showHintTimer = nil; | |
} | |
- (void)hideHintView { | |
[self.hintView removeFromSuperview]; | |
self.hintView = nil; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment