diff --git a/HintMakerExample/EMHint.h b/HintMakerExample/EMHint.h index e0c3071..1786821 100644 --- a/HintMakerExample/EMHint.h +++ b/HintMakerExample/EMHint.h @@ -31,9 +31,9 @@ typedef enum /* - // return a view where the spotlight should shine + // return an array of UIView where spotlights should shine */ --(UIView*)hintStateViewToHint:(id)hintState; +-(NSArray*)hintStateViewsToHint:(id)hintState; /* // the default hint space is a label with white helvetica text dynamically centered, @@ -42,10 +42,10 @@ typedef enum -(UIView*)hintStateViewForDialog:(id)hintState; /* - // return a rect for where the spotlight should shine. - // convenient if a UIView is not an option + // return an array of rects (NSValue objs) for where spotlights should shine. + // convenient if UIView array is not an option */ --(CGRect)hintStateRectToHint:(id)hintState; +-(NSArray*)hintStateRectsToHint:(id)hintState; /* // return NO, if you plan to daisy chain hints, or do someother action diff --git a/HintMakerExample/EMHint.m b/HintMakerExample/EMHint.m index 68ad674..049a590 100644 --- a/HintMakerExample/EMHint.m +++ b/HintMakerExample/EMHint.m @@ -69,23 +69,23 @@ -(void)presentModalMessage:(NSString*)message where:(UIView*)presentationPlace { //incase we have many in a row if(_modalView!=nil) - [_modalView removeFromSuperview]; + [self clear]; - if ([self.hintDelegate respondsToSelector:@selector(hintStateViewToHint:)]) { - UIView *v = [self.hintDelegate hintStateViewToHint:self]; - if(v!=nil) - _modalView = [[EMHintsView alloc] initWithFrame:presentationPlace.frame forView:v]; + if ([self.hintDelegate respondsToSelector:@selector(hintStateViewsToHint:)]) { + NSArray *viewArray = [self.hintDelegate hintStateViewsToHint:self]; + if(viewArray!=nil) + _modalView = [[EMHintsView alloc] initWithFrame:presentationPlace.frame forViews:viewArray]; } - if ([self.hintDelegate respondsToSelector:@selector(hintStateRectToHint:)]) { - CGRect rect = [self.hintDelegate hintStateRectToHint:self]; - if (rect.size.width>0 && rect.size.height>0) - _modalView = [[EMHintsView alloc] initWithFrame:presentationPlace.frame withRect:rect]; + if ([self.hintDelegate respondsToSelector:@selector(hintStateRectsToHint:)]) { + NSArray* rectArray = [self.hintDelegate hintStateRectsToHint:self]; + if (rectArray != nil) + _modalView = [[EMHintsView alloc] initWithFrame:presentationPlace.frame withRects:rectArray]; } if (_modalView==nil) - [NSException raise:@"No ModalView protocols" - format:@"you must at least implement a view or point "]; + _modalView = [[EMHintsView alloc] initWithFrame:presentationPlace.frame]; + [_modalView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; [presentationPlace addSubview:_modalView]; diff --git a/HintMakerExample/EMHintsView.h b/HintMakerExample/EMHintsView.h index 49084a7..2a83583 100644 --- a/HintMakerExample/EMHintsView.h +++ b/HintMakerExample/EMHintsView.h @@ -17,9 +17,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI @interface EMHintsView : UIView { - CGPoint _position; - CGFloat _radius; + // array positions of spotlights + NSMutableArray* _positionArray; + // array radius of spotlights + NSMutableArray* _radiusArray; } -- (id)initWithFrame:(CGRect)frame forView:(UIView*)onView; -- (id)initWithFrame:(CGRect)frame withRect:(CGRect)aRect; + +- (id)initWithFrame:(CGRect)frame; +- (id)initWithFrame:(CGRect)frame forViews:(NSArray*)viewArray; +- (id)initWithFrame:(CGRect)frame withRects:(NSArray*)rectArray; @end diff --git a/HintMakerExample/EMHintsView.m b/HintMakerExample/EMHintsView.m index 55b25d5..0e04cdb 100644 --- a/HintMakerExample/EMHintsView.m +++ b/HintMakerExample/EMHintsView.m @@ -20,27 +20,57 @@ @implementation EMHintsView -- (id)initWithFrame:(CGRect)frame withRect:(CGRect)aRect +- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { - // Initialization code - _position = CGPointMake(aRect.origin.x, - aRect.origin.y); - _radius = aRect.size.width; + // initialize arrays + _positionArray = [[NSMutableArray alloc] init]; + _radiusArray = [[NSMutableArray alloc] init]; + + // set background color [self setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:BACKGROUND_ALPHA]]; } return self; } -- (id)initWithFrame:(CGRect)frame forView:(UIView*)onView +- (id)initWithFrame:(CGRect)frame withRects:(NSArray *)rectArray +{ + self = [super initWithFrame:frame]; + if (self) { + _positionArray = [[NSMutableArray alloc] init]; + _radiusArray = [[NSMutableArray alloc] init]; + // add spotlight position and radius + for (NSValue* theRectObj in rectArray) + { + CGRect theRect = [theRectObj CGRectValue]; + CGPoint pos = CGPointMake(theRect.origin.x, theRect.origin.y); + CGFloat radius = theRect.size.width; + [_positionArray addObject:[NSValue valueWithCGPoint:pos]]; + [_radiusArray addObject:[NSNumber numberWithFloat:radius]]; + } + [self setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:BACKGROUND_ALPHA]]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame forViews:(NSArray *)viewArray { self = [super initWithFrame:frame]; if (self) { // Initialization code - _position = CGPointMake(onView.frame.origin.x + (onView.frame.size.width/2) - , onView.frame.origin.y + (onView.frame.size.height/2) ); - _radius = onView.frame.size.width; + _positionArray = [[NSMutableArray alloc] init]; + _radiusArray = [[NSMutableArray alloc] init]; + // add spotlight position and radius + for (UIView* theView in viewArray) + { + CGPoint pos = CGPointMake(theView.frame.origin.x + (theView.frame.size.width/2) + , theView.frame.origin.y + (theView.frame.size.height/2) ); + CGFloat radius = theView.frame.size.width; + [_positionArray addObject:[NSValue valueWithCGPoint:pos]]; + [_radiusArray addObject:[NSNumber numberWithFloat:radius]]; + } + [self setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:BACKGROUND_ALPHA]]; } return self; @@ -48,18 +78,17 @@ - (id)initWithFrame:(CGRect)frame forView:(UIView*)onView -(void)_background:(CGRect)rect { - CGPoint c = _position; - + // context for drawing CGContextRef context = UIGraphicsGetCurrentContext(); CGImageRef backgroundimage = CGBitmapContextCreateImage(context); CGContextClearRect(context, rect); //CGContextDrawImage(context, rect, backgroundimage); - // Draw the masking image + // save state CGContextSaveGState(context); - //flip the context (right-sideup) + // flip the context (right-sideup) CGContextTranslateCTM(context, 0, rect.size.height); CGContextScaleCTM(context, 1.0, -1.0); @@ -76,47 +105,57 @@ -(void)_background:(CGRect)rect CGFloat colorLocations[2] = {0.25,0.5}; - //create the gradient Ref - CGGradientRef gradientRef = CGGradientCreateWithColorComponents(colorspace, components, colorLocations, 2); - CGColorSpaceRelease(colorspace); - - //draw the shape - CGFloat radius =_radius; - CGMutablePathRef path = CGPathCreateMutable(); - // - //draw a rect around view - CGPathAddRect(path, NULL, CGRectMake(c.x - _radius, c.y -radius,100,100)); - CGPathAddLineToPoint(path, NULL, c.x +_radius, c.y - _radius); - CGPathAddLineToPoint(path, NULL, c.x +_radius, c.y + _radius); - CGPathAddLineToPoint(path, NULL, c.x - _radius, c.y + _radius); - CGPathAddLineToPoint(path, NULL, c.x - _radius, c.y); - CGPathAddLineToPoint(path, NULL, c.x, c.y); - /* - - //draw a rectangle like spotlight --- i'll get to this later - CGPathMoveToPoint(path, NULL, c.x-radius, c.y-radius); - CGPathAddLineToPoint(path, NULL, c.x, c.y-radius); - CGPathAddArcToPoint(path, NULL, c.x+radius, c.y-radius, c.x+radius, c.y, radius); - CGPathAddArcToPoint(path, NULL, c.x+radius, c.y +radius, c.x , c.y+radius, radius); - CGPathAddArcToPoint(path, NULL, c.x -radius, c.y + radius, c.x-radius, c.y, radius); - CGPathAddArcToPoint(path, NULL, c.x-radius, c.y - radius, c.x, c.y-radius, radius); - CGContextAddPath(context, path); - CGContextClip(context); - - //fill with gradient - CGContextDrawRadialGradient(context, gradientRef, c, 0.0f, c, _radius*2, 0); - - - */ - - - CGContextAddPath(context, path); - CGPathRelease(path); - CGContextClip(context); + // draw spotlights + int spotlightCount = _positionArray.count; + for (int i=0; i> #pragma mark -------------->>hint deleage --(UIView*)hintStateViewToHint:(id)hintState +-(NSArray*)hintStateViewsToHint:(id)hintState { - return _info; + return [[NSArray alloc] initWithObjects:_info, nil]; } -(UIView*)hintStateViewForDialog:(id)hintState { diff --git a/HintMakerExample/HintHelper.h b/HintMakerExample/HintHelper.h index 9d23c68..4d72d52 100644 --- a/HintMakerExample/HintHelper.h +++ b/HintMakerExample/HintHelper.h @@ -24,6 +24,7 @@ typedef enum EMHintDialogTypeButton, EMHintDialogTypeList, EMHintDialogTypeBack, + EMHintDialogTypeListAndBack, EMHintDialogTypeCount }EMHintDialogType; diff --git a/HintMakerExample/HintHelper.m b/HintMakerExample/HintHelper.m index 64f198b..477b933 100644 --- a/HintMakerExample/HintHelper.m +++ b/HintMakerExample/HintHelper.m @@ -30,6 +30,9 @@ -(void)doNext case EMHintDialogTypeList: [modalState presentModalMessage:@"This is a list button! \r\nProtocol: returned rect" where:_vc.navigationController.view]; break; + case EMHintDialogTypeListAndBack: + [modalState presentModalMessage:@"Multiple spotlights: list and back button \r\nProtocol: returned rect" where:_vc.navigationController.view]; + break; default: [modalState presentModalMessage:@"" where:_vc.navigationController.view]; break; @@ -62,31 +65,46 @@ -(void)hintStateDidClose:(id)hintState --(CGRect)hintStateRectToHint:(id)hintState +-(NSArray*)hintStateRectsToHint:(id)hintState { CGFloat ht = 50.0; CGFloat statusBarHt = 20.0; - CGRect rect; + NSArray* rectArray = nil; switch (_curType) { case EMHintDialogTypeInfo: - rect = CGRectMake(_vc.view.frame.size.width/2 , - _vc.view.frame.size.height/2 + (statusBarHt + 44), - ht,ht); + { + CGRect rect = CGRectMake(_vc.view.frame.size.width/2 , + _vc.view.frame.size.height/2 + (statusBarHt + 44), + ht,ht); + rectArray = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:rect], nil]; + } break; case EMHintDialogTypeList: - rect = CGRectMake(290, ht/2 + statusBarHt,ht,ht); + { + CGRect rect = CGRectMake(290, ht/2 + statusBarHt,ht,ht); + rectArray = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:rect], nil]; + } break; case EMHintDialogTypeBack: - rect= CGRectMake(25, ht/2 + statusBarHt,ht,ht); + { + CGRect rect= CGRectMake(25, ht/2 + statusBarHt,ht,ht); + rectArray = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:rect], nil]; + } + break; + case EMHintDialogTypeListAndBack: + { + CGRect backRect = CGRectMake(25, ht/2 + statusBarHt,ht,ht); + CGRect listRect = CGRectMake(290, ht/2 + statusBarHt,ht,ht); + rectArray = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:backRect], [NSValue valueWithCGRect:listRect], nil]; + } break; + case EMHintDialogTypeButton: - rect = CGRectMake(0, 0, 1, 1); break; default: - rect = CGRectMake(0, 0, 1, 1); break; } - return rect; + return rectArray; } diff --git a/README.md b/README.md index 590ab8f..b537ba6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Overview -**EMHint** is an iOS class group that easily adds a spotlight-like effect to a view highlighting or hinting at something that may be important on the screen.The protocols of EMHintDelegate allow users to override many of the default actions and views. Tapping the black overlay fades it away. +**EMHint** is an iOS class group that easily adds multiple spotlight-like effects to a view highlighting or hinting at some things that may be important on the screen.The protocols of EMHintDelegate allow users to override many of the default actions and views. Tapping the black overlay fades it away. Great for quick "how to" or tutorials in your app.