Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions WSCoachMarksView.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@
#endif
#endif

typedef enum {
WS_LABEL_ALIGNMENT_CENTER,
WS_LABEL_ALIGNMENT_LEFT,
WS_LABEL_ALIGNMENT_RIGHT,
} WS_LABEL_ALIGNMENT;

typedef enum {
WS_LABEL_POSITION_BOTTOM,
WS_LABEL_POSITION_LEFT,
WS_LABEL_POSITION_TOP,
WS_LABEL_POSITION_RIGHT,
WS_LABEL_POSITION_RIGHT_BOTTOM
} WS_LABEL_POSITION;

@protocol WSCoachMarksViewDelegate;

@interface WSCoachMarksView : UIView
Expand All @@ -51,6 +65,7 @@
@property (nonatomic) CGFloat maxLblWidth;
@property (nonatomic) CGFloat lblSpacing;
@property (nonatomic) BOOL enableContinueLabel;
@property (nonatomic, strong) UIImageView *arrowImage;

- (id)initWithFrame:(CGRect)frame coachMarks:(NSArray *)marks;
- (void)start;
Expand All @@ -60,9 +75,10 @@
@protocol WSCoachMarksViewDelegate <NSObject>

@optional
- (void)coachMarksView:(WSCoachMarksView*)coachMarksView willNavigateToIndex:(NSUInteger)index;
- (void)coachMarksView:(WSCoachMarksView*)coachMarksView didNavigateToIndex:(NSUInteger)index;
- (void)coachMarksView:(WSCoachMarksView*)coachMarksView willNavigateToIndex:(NSInteger)index;
- (void)coachMarksView:(WSCoachMarksView*)coachMarksView didNavigateToIndex:(NSInteger)index;
- (void)coachMarksViewWillCleanup:(WSCoachMarksView*)coachMarksView;
- (void)coachMarksViewDidCleanup:(WSCoachMarksView*)coachMarksView;
- (void)coachMarksViewDidClicked:(WSCoachMarksView*)coachMarksView atIndex:(NSInteger)index;
@end

@end
142 changes: 133 additions & 9 deletions WSCoachMarksView.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//
// WSCoachMarksView.m
// Version 0.2
// Version 0.22
//
// Created by Dimitry Bentsionov on 4/1/13.
// Modified by Roman Barzyczack on 7/8.2013
// Copyright (c) 2013 Workshirt, Inc. All rights reserved.
//

Expand All @@ -13,12 +14,15 @@
static const CGFloat kCutoutRadius = 2.0f;
static const CGFloat kMaxLblWidth = 230.0f;
static const CGFloat kLblSpacing = 35.0f;
static const CGFloat kLabelMargin = 5.0f;
static const CGFloat kMaskAlpha = 0.75f;
static const BOOL kEnableContinueLabel = YES;

@implementation WSCoachMarksView {
CAShapeLayer *mask;
NSUInteger markIndex;
UILabel *lblContinue;
UIView *currentView;
}

#pragma mark - Properties
Expand Down Expand Up @@ -76,7 +80,7 @@ - (void)setup {
// Shape layer mask
mask = [CAShapeLayer layer];
[mask setFillRule:kCAFillRuleEvenOdd];
[mask setFillColor:[[UIColor colorWithHue:0.0f saturation:0.0f brightness:0.0f alpha:0.9f] CGColor]];
[mask setFillColor:[[UIColor colorWithHue:0.0f saturation:0.0f brightness:0.0f alpha:kMaskAlpha] CGColor]];
[self.layer addSublayer:mask];

// Capture touches
Expand All @@ -88,6 +92,7 @@ - (void)setup {
self.lblCaption.backgroundColor = [UIColor clearColor];
self.lblCaption.textColor = [UIColor whiteColor];
self.lblCaption.font = [UIFont systemFontOfSize:20.0f];
self.lblCaption.font = [UIFont fontWithName:@"Noteworthy-Light" size:20.0f];
self.lblCaption.lineBreakMode = NSLineBreakByWordWrapping;
self.lblCaption.numberOfLines = 0;
self.lblCaption.textAlignment = NSTextAlignmentCenter;
Expand Down Expand Up @@ -159,7 +164,13 @@ - (void)start {
}];
}

- (void)goToCoachMarkIndexed:(NSUInteger)index {
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
[self.delegate coachMarksViewDidClicked:self atIndex:markIndex];
[self cleanup];
}

- (void)goToCoachMarkIndexed:(NSInteger)index {

// Out of bounds
if (index >= self.coachMarks.count) {
[self cleanup];
Expand All @@ -173,7 +184,31 @@ - (void)goToCoachMarkIndexed:(NSUInteger)index {
NSDictionary *markDef = [self.coachMarks objectAtIndex:index];
NSString *markCaption = [markDef objectForKey:@"caption"];
CGRect markRect = [[markDef objectForKey:@"rect"] CGRectValue];

WS_LABEL_ALIGNMENT labelAlignment = [[markDef objectForKey:@"alignment"] integerValue];
WS_LABEL_POSITION labelPosition = [[markDef objectForKey:@"position"] integerValue];
if([markDef objectForKey:@"cutoutRadius"]) {
self.cutoutRadius = [[markDef objectForKey:@"cutoutRadius"] floatValue];
} else {
self.cutoutRadius = kCutoutRadius;
}

if ([self.delegate respondsToSelector:@selector(coachMarksViewDidClicked:atIndex:)]) {
[currentView removeFromSuperview];
currentView = [[UIView alloc] initWithFrame:markRect];
currentView.backgroundColor = [UIColor clearColor];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSingleTap:)];
[currentView addGestureRecognizer:singleFingerTap];
[self addSubview:currentView];
}



BOOL showArrow = YES;
if( [markDef objectForKey:@"showArrow"]) {
showArrow = [[markDef objectForKey:@"showArrow"] boolValue];
}
// Delegate (coachMarksView:willNavigateTo:atIndex:)
if ([self.delegate respondsToSelector:@selector(coachMarksView:willNavigateToIndex:)]) {
[self.delegate coachMarksView:self willNavigateToIndex:markIndex];
Expand All @@ -184,12 +219,101 @@ - (void)goToCoachMarkIndexed:(NSUInteger)index {
self.lblCaption.frame = (CGRect){{0.0f, 0.0f}, {self.maxLblWidth, 0.0f}};
self.lblCaption.text = markCaption;
[self.lblCaption sizeToFit];
CGFloat y = markRect.origin.y + markRect.size.height + self.lblSpacing;
CGFloat bottomY = y + self.lblCaption.frame.size.height + self.lblSpacing;
if (bottomY > self.bounds.size.height) {
y = markRect.origin.y - self.lblSpacing - self.lblCaption.frame.size.height;
CGFloat y;
CGFloat x;
[self.arrowImage removeFromSuperview];
switch (labelAlignment) {
case WS_LABEL_ALIGNMENT_RIGHT:
x =floorf(self.bounds.size.width - self.lblCaption.frame.size.width - kLabelMargin);
break;
case WS_LABEL_ALIGNMENT_LEFT:
x = kLabelMargin;
break;
default:
x =floorf((self.bounds.size.width - self.lblCaption.frame.size.width) / 2.0f);
break;
}

switch (labelPosition) {
case WS_LABEL_POSITION_TOP:
{
y = markRect.origin.y - self.lblCaption.frame.size.height - kLabelMargin;
if(showArrow) {
self.arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow-bottom.png"]];
CGRect imageViewFrame = self.arrowImage.frame;
imageViewFrame.origin.x = x;
imageViewFrame.origin.y = y;
self.arrowImage.frame = imageViewFrame;
y -= (self.arrowImage.frame.size.height + kLabelMargin);
[self addSubview:self.arrowImage];
}
}
break;
case WS_LABEL_POSITION_LEFT:
{
y = markRect.origin.y + markRect.size.height/2 - self.lblCaption.frame.size.height/2;
x = self.bounds.size.width - self.lblCaption.frame.size.width - kLabelMargin - markRect.size.width;
if(showArrow) {
self.arrowImage= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow-right.png"]];
CGRect imageViewFrame = self.arrowImage.frame;
imageViewFrame.origin.x = self.bounds.size.width - self.arrowImage.frame.size.width - kLabelMargin - markRect.size.width;
imageViewFrame.origin.y = y + self.lblCaption.frame.size.height/2 - imageViewFrame.size.height/2;
self.arrowImage.frame = imageViewFrame;
x -= (self.arrowImage.frame.size.width + kLabelMargin);
[self addSubview:self.arrowImage];
}
}
break;
case WS_LABEL_POSITION_RIGHT:
{
y = markRect.origin.y + markRect.size.height/2 - self.lblCaption.frame.size.height/2;
x = markRect.origin.x + markRect.size.width + kLabelMargin;
if(showArrow) {

}
}
break;
case WS_LABEL_POSITION_RIGHT_BOTTOM:
{
y = markRect.origin.y + markRect.size.height + self.lblSpacing;
CGFloat bottomY = y + self.lblCaption.frame.size.height + self.lblSpacing;
if (bottomY > self.bounds.size.height) {
y = markRect.origin.y - self.lblSpacing - self.lblCaption.frame.size.height;
}
x = markRect.origin.x + markRect.size.width + kLabelMargin;
if(showArrow) {
self.arrowImage= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow-top.png"]];
CGRect imageViewFrame = self.arrowImage.frame;
imageViewFrame.origin.x = x - markRect.size.width/2 - imageViewFrame.size.width/2;
imageViewFrame.origin.y = y - kLabelMargin; //self.lblCaption.frame.size.height/2
y += imageViewFrame.size.height/2;
self.arrowImage.frame = imageViewFrame;
[self addSubview:self.arrowImage];
}
}
break;
default: {
y = markRect.origin.y + markRect.size.height + self.lblSpacing;
CGFloat bottomY = y + self.lblCaption.frame.size.height + self.lblSpacing;
if (bottomY > self.bounds.size.height) {
y = markRect.origin.y - self.lblSpacing - self.lblCaption.frame.size.height;
}
if(showArrow) {
self.arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow-top.png"]];
CGRect imageViewFrame = self.arrowImage.frame;
imageViewFrame.origin.x = x;
imageViewFrame.origin.y = y;
self.arrowImage.frame = imageViewFrame;
y += (self.arrowImage.frame.size.height + kLabelMargin);
[self addSubview:self.arrowImage];
}
}
break;
}
CGFloat x = floorf((self.bounds.size.width - self.lblCaption.frame.size.width) / 2.0f);





// Animate the caption label
self.lblCaption.frame = (CGRect){{x, y}, self.lblCaption.frame.size};
Expand Down
Binary file added images/arrow-down.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/arrow-ios.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/arrow-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/arrow-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/arrow-top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.