From 5f51c0cd66868fd988a4c287b69ce5d03046ad4d Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Tue, 10 Jan 2017 15:30:24 +0000 Subject: [PATCH 1/6] Add support for titles --- Coach Marks/DDBubble.h | 4 +- Coach Marks/DDBubble.m | 90 ++++++++++++++++++++++++++-------- Coach Marks/DDCoachMarksView.m | 10 ++-- README.md | 8 ++- 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/Coach Marks/DDBubble.h b/Coach Marks/DDBubble.h index 3fbd8a9..91a00dc 100755 --- a/Coach Marks/DDBubble.h +++ b/Coach Marks/DDBubble.h @@ -26,10 +26,12 @@ typedef enum { @property (nonatomic) BOOL bouncing; @property (nonatomic) BOOL animationShouldStop; @property (nonatomic) UIFont *font; +@property (nonatomic) UIFont *titleFont; -(id)initWithAttachedView:(UIView*)view title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition andColor:(UIColor*)color; -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition andColor:(UIColor*)color; -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition color:(UIColor*)color andFont:(UIFont *)font; +-(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition color:(UIColor*)color andFont:(UIFont *)font titleFont:(UIFont*)titleFont; -(void)animate; -@end \ No newline at end of file +@end diff --git a/Coach Marks/DDBubble.m b/Coach Marks/DDBubble.m index 00d7362..057495a 100755 --- a/Coach Marks/DDBubble.m +++ b/Coach Marks/DDBubble.m @@ -38,6 +38,11 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d } -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition color:(UIColor*)color andFont:(UIFont *)font +{ + return [self initWithFrame:frame title:title description:description arrowPosition:arrowPosition color:color andFont:font titleFont:nil]; +} + +-(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)description arrowPosition:(CRArrowPosition)arrowPosition color:(UIColor*)color andFont:(UIFont *)font titleFont:(UIFont*)titleFont { self = [super init]; if(self) @@ -50,7 +55,12 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d if (font != nil) self.font = font; else - self.font = [UIFont fontWithName:@"HelveticaNeue" size:DEFAULT_TITLE_FONT_SIZE]; + self.font = [UIFont systemFontOfSize:DEFAULT_TITLE_FONT_SIZE]; + + if (titleFont != nil) + self.titleFont = titleFont; + else + self.titleFont = [UIFont boldSystemFontOfSize:DEFAULT_TITLE_FONT_SIZE]; self.attachedFrame = frame; self.title = title; @@ -60,7 +70,7 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d } // position bubble - [self setFrame:[self calculateFrameWithFont:self.font]]; + [self setFrame:[self calculateFrame]]; [self fixFrameIfOutOfBounds]; // Make it pass touch events through to the DDCoachMarksView @@ -73,16 +83,48 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d float actualWidth = self.frame.size.width-actualXPosition - PADDING*1.5; float actualHeight = self.frame.size.height - actualYPosition - PADDING*1.2; - UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(actualXPosition, actualYPosition, actualWidth, actualHeight)]; - [titleLabel setFont:self.font]; - [titleLabel setTextColor:TEXT_COLOR]; - [titleLabel setAlpha:0.9]; - [titleLabel setText:title]; - [titleLabel setBackgroundColor:[UIColor clearColor]]; - [titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; - [titleLabel setNumberOfLines:0]; - [titleLabel setUserInteractionEnabled:NO]; - [self addSubview:titleLabel]; + UILabel *titleLabel = nil; + + if (title.length > 0) { + titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(actualXPosition, actualYPosition, actualWidth, actualHeight)]; + [titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; + [titleLabel setFont:self.titleFont]; + [titleLabel setTextColor:TEXT_COLOR]; + [titleLabel setAlpha:0.9]; + [titleLabel setText:title]; + [titleLabel setBackgroundColor:[UIColor clearColor]]; + [titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; + [titleLabel setNumberOfLines:0]; + [titleLabel setUserInteractionEnabled:NO]; + [self addSubview:titleLabel]; + + [self addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:actualYPosition]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:(-offsets.width - PADDING*3.0 + 1)]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:actualXPosition]]; + } + + if (description.length > 0) { + UILabel *bodyLabel = [[UILabel alloc] initWithFrame:CGRectMake(actualXPosition, actualYPosition, actualWidth, actualHeight)]; + [bodyLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; + [bodyLabel setFont:self.font]; + [bodyLabel setTextColor:TEXT_COLOR]; + [bodyLabel setAlpha:0.9]; + [bodyLabel setText:description]; + [bodyLabel setBackgroundColor:[UIColor clearColor]]; + [bodyLabel setLineBreakMode:NSLineBreakByWordWrapping]; + [bodyLabel setNumberOfLines:0]; + [bodyLabel setUserInteractionEnabled:NO]; + [self addSubview:bodyLabel]; + + if (titleLabel != nil) { + // Add some constraints + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; + } else { + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:actualYPosition]]; + } + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:(-offsets.width - PADDING*3.0 + 1)]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:actualXPosition]]; + } [self setNeedsDisplay]; return self; @@ -130,14 +172,14 @@ - (void)fixFrameIfOutOfBounds self.arrowPosition = CRArrowPositionBottom; // Restart the entire process - CGRect flippedFrame = [self calculateFrameWithFont:[self font]]; + CGRect flippedFrame = [self calculateFrame]; y = flippedFrame.origin.y; height = flippedFrame.size.height; } else if ((self.arrowPosition == CRArrowPositionBottom) && (y < 0)) { self.arrowPosition = CRArrowPositionTop; // Restart the entire process - CGRect flippedFrame = [self calculateFrameWithFont:[self font]]; + CGRect flippedFrame = [self calculateFrame]; y = flippedFrame.origin.y; height = flippedFrame.size.height; } @@ -145,13 +187,13 @@ - (void)fixFrameIfOutOfBounds [self setFrame:CGRectMake(x, y, width, height)]; } --(CGRect)calculateFrameWithFont:(UIFont*)font +-(CGRect)calculateFrame { //Calculation of the bubble position float x = self.attachedFrame.origin.x; float y = self.attachedFrame.origin.y; - CGSize size = [self sizeWithFont:font]; + CGSize size = [self calculateSize]; float widthDelta = 0, heightDelta = 0; @@ -171,7 +213,7 @@ -(CGRect)calculateFrameWithFont:(UIFont*)font return CGRectMake(x, y, size.width+widthDelta, size.height+heightDelta); } --(CGSize)sizeWithFont:(UIFont*)font +-(CGSize)calculateSize { // Calcultation of the bubble size // size of bubble title determined by the strings attributes @@ -184,9 +226,17 @@ -(CGSize)sizeWithFont:(UIFont*)font widthDelta = ARROW_SIZE; } - CGSize result = [_title sizeWithFont:font constrainedToSize:CGSizeMake(window.size.width - widthDelta - (PADDING*3), FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; + CGSize titleResult = CGSizeZero; + if (self.title.length > 0) { + titleResult = [self.title sizeWithFont:self.titleFont constrainedToSize:CGSizeMake(window.size.width - widthDelta - (PADDING*3), FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; + } + + CGSize result = CGSizeZero; + if (self.bubbleText.length > 0) { + result = [self.bubbleText sizeWithFont:self.font constrainedToSize:CGSizeMake(window.size.width - widthDelta - (PADDING*3), FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; + } - return CGSizeMake(result.width + (PADDING*3), result.height + (PADDING*2.5)); + return CGSizeMake(MAX(titleResult.width, result.width) + (PADDING*3), titleResult.height + result.height + (PADDING*2.5)); } -(CGSize)offsets @@ -204,7 +254,7 @@ - (void)drawRect:(CGRect)rect CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); - CGSize size = [self sizeWithFont:[self font]]; + CGSize size = [self calculateSize]; CGPathRef clippath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake([self offsets].width,[self offsets].height, size.width, size.height) cornerRadius:RADIUS].CGPath; CGContextAddPath(ctx, clippath); diff --git a/Coach Marks/DDCoachMarksView.m b/Coach Marks/DDCoachMarksView.m index 9330a7c..39bb8d8 100755 --- a/Coach Marks/DDCoachMarksView.m +++ b/Coach Marks/DDCoachMarksView.m @@ -250,10 +250,12 @@ - (void)animateNextBubble { // Get current coach mark information NSDictionary *coachMarkInfo = [self.coachMarks objectAtIndex:markIndex]; + NSString *markTitle = [coachMarkInfo objectForKey:@"title"]; NSString *markCaption = [coachMarkInfo objectForKey:@"caption"]; CGRect frame = [[coachMarkInfo objectForKey:@"rect"] CGRectValue]; CGRect poi = [[coachMarkInfo objectForKey:@"POI"] CGRectValue]; UIFont *font = [coachMarkInfo objectForKey:@"font"]; + UIFont *titleFont = [coachMarkInfo objectForKey:@"titlefont"]; // remove previous bubble if (self.bubble) { @@ -264,16 +266,16 @@ - (void)animateNextBubble } // return if no text for bubble - if ([markCaption length] == 0) + if (([markCaption length] == 0) && ([markTitle length] == 0)) return; // create bubble // IF using point of interest (poi) frame use that instead of cutout frame // ELSE use the cutout frame if (CGRectIsEmpty(poi)) { - self.bubble = [[DDBubble alloc] initWithFrame:frame title:markCaption description:nil arrowPosition:CRArrowPositionTop color:nil andFont:font]; + self.bubble = [[DDBubble alloc] initWithFrame:frame title:markTitle description:markCaption arrowPosition:CRArrowPositionTop color:nil andFont:font titleFont:titleFont]; } else - self.bubble = [[DDBubble alloc] initWithFrame:poi title:markCaption description:nil arrowPosition:CRArrowPositionTop color:nil andFont:font]; + self.bubble = [[DDBubble alloc] initWithFrame:poi title:markTitle description:markCaption arrowPosition:CRArrowPositionTop color:nil andFont:font titleFont:titleFont]; self.bubble.alpha = 0.0; [self addSubview:self.bubble]; @@ -336,4 +338,4 @@ - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { } } -@end \ No newline at end of file +@end diff --git a/README.md b/README.md index 90e43bf..fd3c3be 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,9 @@ coachMarksView.useBubbles = NO; When creating your array of dictionary definitions for each coach mark only the `@"rect"` value is required. Other optional values are: * `@"caption"` -Text that goes in the bubbles + Text that goes in the bubbles +* `@"title"` + An optional title to go above the caption * `@"shape"` Can be set to circle or square. If nothing is defined, the default is a rounded rect. * `@"POI"` @@ -95,7 +97,9 @@ Text that goes in the bubbles * `@"direction"` Direction that swipe gestures should animate in. The default is `@"lefttoright"` but you can also specify `@"righttoleft"`. * `@"font"` - Font for the caption in the bubble. If not specified, defaults to the default HelveticaNeue size 14.0. + Font for the caption in the bubble. If not specified, defaults to the system font size 14.0. +* `@"titlefont"` + Font for the title caption in the bubble. If not specified, defaults to the bold system font size 14.0. ## DDCoachMarksViewDelegate From e2833c421c55e7bc9184d6cd5d7b924189477ca7 Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Wed, 11 Jan 2017 11:54:15 +0000 Subject: [PATCH 2/6] Allow touches inside the cutout area to fall through to the view below --- Coach Marks/DDCoachMarksView.h | 3 ++- Coach Marks/DDCoachMarksView.m | 16 +++++++++++++++- README.md | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Coach Marks/DDCoachMarksView.h b/Coach Marks/DDCoachMarksView.h index 1053544..0409ff9 100755 --- a/Coach Marks/DDCoachMarksView.h +++ b/Coach Marks/DDCoachMarksView.h @@ -21,6 +21,7 @@ @property (nonatomic) CGFloat maxLblWidth; @property (nonatomic) CGFloat lblSpacing; @property (nonatomic) BOOL useBubbles; +@property (nonatomic) BOOL transmitTouchesInCutout; - (id)initWithFrame:(CGRect)frame coachMarks:(NSArray *)marks; - (void)setMaskColor:(UIColor *)maskColor; @@ -37,4 +38,4 @@ - (void)coachMarksViewDidCleanup:(DDCoachMarksView*)coachMarksView; - (void)didTapAtIndex:(NSUInteger)index; -@end \ No newline at end of file +@end diff --git a/Coach Marks/DDCoachMarksView.m b/Coach Marks/DDCoachMarksView.m index 39bb8d8..bc34b01 100755 --- a/Coach Marks/DDCoachMarksView.m +++ b/Coach Marks/DDCoachMarksView.m @@ -141,6 +141,18 @@ - (void)setMaskColor:(UIColor *)maskColor { #pragma mark - Touch handler +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + + // See if tap was inside the cutout or not + BOOL isOutsideCutout = !self.transmitTouchesInCutout || CGPathContainsPoint(mask.path, NULL, point, true); + + if (!isOutsideCutout) { + [self cleanup]; + } + + return isOutsideCutout; +} + - (void)userDidTap:(UITapGestureRecognizer *)recognizer { if ([self.delegate respondsToSelector:@selector(didTapAtIndex:)]) { @@ -301,7 +313,9 @@ - (void)cleanup { __weak DDCoachMarksView *weakSelf = self; // animate & remove from super view - [UIView animateWithDuration:0.6 delay:0.3 options:0 + // Need UIViewAnimationOptionAllowUserInteraction option if triggered by touching inside the cutout, + // else it cancels the touch that triggered the cleanup in the first place + [UIView animateWithDuration:0.6 delay:0.3 options:UIViewAnimationOptionAllowUserInteraction animations:^{ self.alpha = 0.0f; self.animatingCircle.alpha = 0.0f; diff --git a/README.md b/README.md index fd3c3be..3999521 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ You can configure any coach mark properties before calling the `start` method. F coachMarksView.animationDuration = 0.5f; coachMarksView.maskColor = [UIColor blueColor]; coachMarksView.useBubbles = NO; +coachMarksView.transmitTouchesInCutout = NO; // Don't allow the user to interact with the element being showcased (default) [coachMarksView start]; ``` From ee62c305c981a15e2d870d17f4a994fe530f82b5 Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Wed, 11 Jan 2017 17:52:46 +0000 Subject: [PATCH 3/6] Allow rect to be calculated based on the position of an existing view --- Coach Marks/DDCoachMarksView.m | 44 ++++++++++++++++++++++++++-------- README.md | 6 ++++- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Coach Marks/DDCoachMarksView.m b/Coach Marks/DDCoachMarksView.m index bc34b01..77a8a2d 100755 --- a/Coach Marks/DDCoachMarksView.m +++ b/Coach Marks/DDCoachMarksView.m @@ -196,7 +196,7 @@ - (void)goToCoachMarkIndexed:(NSUInteger)index { // Coach mark definition NSDictionary *markDef = [self.coachMarks objectAtIndex:index]; - CGRect markRect = [[markDef objectForKey:@"rect"] CGRectValue]; + CGRect markRect = [self frameFromCoachMark:markDef]; NSString *shape = [markDef objectForKey:@"shape"]; if (self.useBubbles) { @@ -222,7 +222,7 @@ - (void)goToCoachMarkIndexed:(NSUInteger)index { - (void)showSwipeGesture { NSDictionary *coachMarkInfo = [self.coachMarks objectAtIndex:markIndex]; - CGRect frame = [[coachMarkInfo objectForKey:@"rect"] CGRectValue]; + CGRect frame = [self frameFromCoachMark:coachMarkInfo]; BOOL shouldAnimateSwipe = [[coachMarkInfo objectForKey:@"swipe"] boolValue]; NSString* swipeDirection = [coachMarkInfo objectForKey:@"direction"]; @@ -258,14 +258,42 @@ - (void)showSwipeGesture #pragma mark - Bubble Caption +- (CGRect)frameFromCoachMark:(NSDictionary*)coachMarkInfo { + CGRect frame = [[coachMarkInfo objectForKey:@"rect"] CGRectValue]; + CGRect poi = [[coachMarkInfo objectForKey:@"POI"] CGRectValue]; + UIView *attachedView = [coachMarkInfo objectForKey:@"attachedview"]; + NSValue *transformValue = [coachMarkInfo objectForKey:@"transform"]; + + // IF using point of interest (poi) frame use that instead of cutout frame + // ELSE use the cutout frame + CGRect viewBounds = CGRectZero; + if (attachedView != nil) { + viewBounds = attachedView.bounds; + } else if (CGRectIsEmpty(poi)) { + viewBounds = frame; + } else { + viewBounds = poi; + } + + if (transformValue != nil) { + // Apply the given transform + CGAffineTransform transform = [transformValue CGAffineTransformValue]; + viewBounds = CGRectApplyAffineTransform(viewBounds, transform); + } + + if (attachedView != nil) { + viewBounds = [attachedView convertRect:viewBounds toView:self]; + } + + return viewBounds; +} + - (void)animateNextBubble { // Get current coach mark information NSDictionary *coachMarkInfo = [self.coachMarks objectAtIndex:markIndex]; NSString *markTitle = [coachMarkInfo objectForKey:@"title"]; NSString *markCaption = [coachMarkInfo objectForKey:@"caption"]; - CGRect frame = [[coachMarkInfo objectForKey:@"rect"] CGRectValue]; - CGRect poi = [[coachMarkInfo objectForKey:@"POI"] CGRectValue]; UIFont *font = [coachMarkInfo objectForKey:@"font"]; UIFont *titleFont = [coachMarkInfo objectForKey:@"titlefont"]; @@ -282,12 +310,8 @@ - (void)animateNextBubble return; // create bubble - // IF using point of interest (poi) frame use that instead of cutout frame - // ELSE use the cutout frame - if (CGRectIsEmpty(poi)) { - self.bubble = [[DDBubble alloc] initWithFrame:frame title:markTitle description:markCaption arrowPosition:CRArrowPositionTop color:nil andFont:font titleFont:titleFont]; - } else - self.bubble = [[DDBubble alloc] initWithFrame:poi title:markTitle description:markCaption arrowPosition:CRArrowPositionTop color:nil andFont:font titleFont:titleFont]; + CGRect frame = [self frameFromCoachMark:coachMarkInfo]; + self.bubble = [[DDBubble alloc] initWithFrame:frame title:markTitle description:markCaption arrowPosition:CRArrowPositionTop color:nil andFont:font titleFont:titleFont]; self.bubble.alpha = 0.0; [self addSubview:self.bubble]; diff --git a/README.md b/README.md index 3999521..8721b19 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Create a new DDCoachMarksView instance and pass in an array of coach mark defini @"shape": @"circle", }, @{ - @"rect": [NSValue valueWithCGRect:CGRectMake(0, 125, 320, 60)], + @"attachedview": self.viewToHighlight, @"caption": @"Swipe for more options", @"shape": @"square", @"swipe": @"YES", @@ -93,6 +93,10 @@ Other optional values are: Can be set to circle or square. If nothing is defined, the default is a rounded rect. * `@"POI"` Stands for 'point of interest'. You can define a whole region using the `@"rect"` value, but defining a different CGRect value here makes the bubble caption position itself under the POI rect. +* `@"attachedview"` + Specify a specific UIView to highlight instead of a manually specified `@"rect"` or `@"POI"`. +* `@"transform"` + Specify an optional CGAffineTransform that will be applied to the `@"rect"`, `@"POI"` or `@"attachedview"` frame. Especially useful if you want to modify the frame of the `@"attachedview"` in any way before highlighting. * `@"swipe"` Use "YES" here if you want to show a row swipe gesture on a table view cell. Disabled by default. * `@"direction"` From 3e4bb0fb6a99a994b3239f03a4825a94f9e0f0c7 Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Thu, 12 Jan 2017 09:54:39 +0000 Subject: [PATCH 4/6] For what it's worth, don't break on iOS<6 --- Coach Marks/DDBubble.m | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Coach Marks/DDBubble.m b/Coach Marks/DDBubble.m index 057495a..ba938d5 100755 --- a/Coach Marks/DDBubble.m +++ b/Coach Marks/DDBubble.m @@ -85,7 +85,7 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d UILabel *titleLabel = nil; - if (title.length > 0) { + if ((title.length > 0) && ([self respondsToSelector:@selector(addConstraint:)])) { titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(actualXPosition, actualYPosition, actualWidth, actualHeight)]; [titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; [titleLabel setFont:self.titleFont]; @@ -105,7 +105,9 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d if (description.length > 0) { UILabel *bodyLabel = [[UILabel alloc] initWithFrame:CGRectMake(actualXPosition, actualYPosition, actualWidth, actualHeight)]; - [bodyLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; + if ([bodyLabel respondsToSelector:@selector(setTranslatesAutoresizingMaskIntoConstraints:)]) { + [bodyLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; + } [bodyLabel setFont:self.font]; [bodyLabel setTextColor:TEXT_COLOR]; [bodyLabel setAlpha:0.9]; @@ -116,14 +118,16 @@ -(id)initWithFrame:(CGRect)frame title:(NSString*)title description:(NSString*)d [bodyLabel setUserInteractionEnabled:NO]; [self addSubview:bodyLabel]; - if (titleLabel != nil) { - // Add some constraints - [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; - } else { - [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:actualYPosition]]; + if ([bodyLabel respondsToSelector:@selector(setTranslatesAutoresizingMaskIntoConstraints:)]) { + if (titleLabel != nil) { + // Add some constraints + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; + } else { + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:actualYPosition]]; + } + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:(-offsets.width - PADDING*3.0 + 1)]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:actualXPosition]]; } - [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:(-offsets.width - PADDING*3.0 + 1)]]; - [self addConstraint:[NSLayoutConstraint constraintWithItem:bodyLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:actualXPosition]]; } [self setNeedsDisplay]; From 5ea86f47474e90fb9b3518cebaed867e27503a50 Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Thu, 12 Jan 2017 09:54:55 +0000 Subject: [PATCH 5/6] Git ignore .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + 2 files changed, 1 insertion(+) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index daa9c9285993b5972e6cda93a337ed5d093f02d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKTZ6c6 zUf%?NgXm8Y^l@MOE%lrvN-x`oB508uIQf#y`I5|+OfmrgR_g|301E&Nbi(`@OinO* zPCjEfRdW`Ri8ey8;V!t)foC((x0W#rom3<0#EarDK*`$)7sCYM5rhESx)Ec;tk<=VWfyO>1uFA(igC zS?H$^vQILhAQB`3W zrePjhYyJL4WvghHuU#J$?S8qmQ7PJ+rLDoh`d}JsS1LDdd;I0A*Kgjwd;jUPcu8Qm zu?f4N@E3f+%pBo@)Q>%U1qz)L^4#epF;9*#f;zZ#@(jRLc!9IRA%G^daaZN=bZS<< zB71!#408*$6d#oxpSRkA2Ok$?w|KoCbTc2|o9olMSg7w75B`AN4#!9So%*)sD7c5p zrI5kYYG%90p;0rnnpfct>|h%WxCah2CRJv~6g{T03A-416Y6-{HE@<%5KJ<1kEa+| zTsl)r+bAsE$n=1;0$PE8tpM#0HacNd;ZUO3IxrDe0K`023&TA9ED*<5SXDTbh)>X% zq#{ZxQ&$Wo=~!>8xT?aTL`esxE+0(w%+w8qiQch&TZ99vO4O-VKr1k*z=|wdbpAKy z-~T5`x}+7*3j9|JuzcOA*YK6p**f!bbk^GFPteIIZYWVuFj2>`$k0)I8C@7YvnhjE VRXCK0HE8-rK**pIt-xPZ;3vD{)Jy;X diff --git a/.gitignore b/.gitignore index de7b430..7c386a9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ xcuserdata/ *.moved-aside *.xccheckout *.xcscmblueprint +.DS_Store ## Obj-C/Swift specific *.hmap From 93939c709619dffc54abe64d7c2300a56d5006c8 Mon Sep 17 00:00:00 2001 From: Andy Geers Date: Fri, 13 Jan 2017 12:21:01 +0000 Subject: [PATCH 6/6] Make sure bubble doesn't go out of bounds when repositioning --- Coach Marks/DDBubble.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Coach Marks/DDBubble.m b/Coach Marks/DDBubble.m index ba938d5..f3e9165 100755 --- a/Coach Marks/DDBubble.m +++ b/Coach Marks/DDBubble.m @@ -177,7 +177,7 @@ - (void)fixFrameIfOutOfBounds // Restart the entire process CGRect flippedFrame = [self calculateFrame]; - y = flippedFrame.origin.y; + y = MAX(flippedFrame.origin.y, 10); height = flippedFrame.size.height; } else if ((self.arrowPosition == CRArrowPositionBottom) && (y < 0)) { self.arrowPosition = CRArrowPositionTop;