173 lines
13 KiB
Objective-C
Executable File
173 lines
13 KiB
Objective-C
Executable File
//
|
|
// YBPopupMenuPath.m
|
|
// YBPopupMenu
|
|
//
|
|
// Created by lyb on 2017/5/9.
|
|
// Copyright © 2017年 lyb. All rights reserved.
|
|
//
|
|
|
|
#import "YBPopupMenuPath.h"
|
|
#import "YBRectConst.h"
|
|
|
|
@implementation YBPopupMenuPath
|
|
|
|
+ (CAShapeLayer *)yb_maskLayerWithRect:(CGRect)rect
|
|
rectCorner:(UIRectCorner)rectCorner
|
|
cornerRadius:(CGFloat)cornerRadius
|
|
arrowWidth:(CGFloat)arrowWidth
|
|
arrowHeight:(CGFloat)arrowHeight
|
|
arrowPosition:(CGFloat)arrowPosition
|
|
arrowDirection:(YBPopupMenuArrowDirection)arrowDirection
|
|
{
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
|
shapeLayer.path = [self yb_bezierPathWithRect:rect rectCorner:rectCorner cornerRadius:cornerRadius borderWidth:0 borderColor:nil backgroundColor:nil arrowWidth:arrowWidth arrowHeight:arrowHeight arrowPosition:arrowPosition arrowDirection:arrowDirection].CGPath;
|
|
return shapeLayer;
|
|
}
|
|
|
|
|
|
+ (UIBezierPath *)yb_bezierPathWithRect:(CGRect)rect
|
|
rectCorner:(UIRectCorner)rectCorner
|
|
cornerRadius:(CGFloat)cornerRadius
|
|
borderWidth:(CGFloat)borderWidth
|
|
borderColor:(UIColor *)borderColor
|
|
backgroundColor:(UIColor *)backgroundColor
|
|
arrowWidth:(CGFloat)arrowWidth
|
|
arrowHeight:(CGFloat)arrowHeight
|
|
arrowPosition:(CGFloat)arrowPosition
|
|
arrowDirection:(YBPopupMenuArrowDirection)arrowDirection
|
|
{
|
|
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
|
|
if (borderColor) {
|
|
[borderColor setStroke];
|
|
}
|
|
if (backgroundColor) {
|
|
[backgroundColor setFill];
|
|
}
|
|
bezierPath.lineWidth = borderWidth;
|
|
rect = CGRectMake(borderWidth / 2, borderWidth / 2, YBRectWidth(rect) - borderWidth, YBRectHeight(rect) - borderWidth);
|
|
CGFloat topRightRadius = 0,topLeftRadius = 0,bottomRightRadius = 0,bottomLeftRadius = 0;
|
|
CGPoint topRightArcCenter,topLeftArcCenter,bottomRightArcCenter,bottomLeftArcCenter;
|
|
|
|
if (rectCorner & UIRectCornerTopLeft) {
|
|
topLeftRadius = cornerRadius;
|
|
}
|
|
if (rectCorner & UIRectCornerTopRight) {
|
|
topRightRadius = cornerRadius;
|
|
}
|
|
if (rectCorner & UIRectCornerBottomLeft) {
|
|
bottomLeftRadius = cornerRadius;
|
|
}
|
|
if (rectCorner & UIRectCornerBottomRight) {
|
|
bottomRightRadius = cornerRadius;
|
|
}
|
|
|
|
if (arrowDirection == YBPopupMenuArrowDirectionTop) {
|
|
topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect));
|
|
topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), arrowHeight + topRightRadius + YBRectX(rect));
|
|
bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
|
|
bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
|
|
if (arrowPosition < topLeftRadius + arrowWidth / 2) {
|
|
arrowPosition = topLeftRadius + arrowWidth / 2;
|
|
}else if (arrowPosition > YBRectWidth(rect) - topRightRadius - arrowWidth / 2) {
|
|
arrowPosition = YBRectWidth(rect) - topRightRadius - arrowWidth / 2;
|
|
}
|
|
[bezierPath moveToPoint:CGPointMake(arrowPosition - arrowWidth / 2, arrowHeight + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowPosition, YBRectTop(rect) + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowPosition + arrowWidth / 2, arrowHeight + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, arrowHeight + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
|
|
|
|
}else if (arrowDirection == YBPopupMenuArrowDirectionBottom) {
|
|
topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect),topLeftRadius + YBRectX(rect));
|
|
topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
|
|
bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect) - arrowHeight);
|
|
bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect) - arrowHeight);
|
|
if (arrowPosition < bottomLeftRadius + arrowWidth / 2) {
|
|
arrowPosition = bottomLeftRadius + arrowWidth / 2;
|
|
}else if (arrowPosition > YBRectWidth(rect) - bottomRightRadius - arrowWidth / 2) {
|
|
arrowPosition = YBRectWidth(rect) - bottomRightRadius - arrowWidth / 2;
|
|
}
|
|
[bezierPath moveToPoint:CGPointMake(arrowPosition + arrowWidth / 2, YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowPosition, YBRectHeight(rect) + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowPosition - arrowWidth / 2, YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectX(rect), topLeftRadius + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect) - arrowHeight)];
|
|
[bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
|
|
|
|
}else if (arrowDirection == YBPopupMenuArrowDirectionLeft) {
|
|
topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect) + arrowHeight,topLeftRadius + YBRectX(rect));
|
|
topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
|
|
bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect) + arrowHeight, YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
|
|
bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
|
|
if (arrowPosition < topLeftRadius + arrowWidth / 2) {
|
|
arrowPosition = topLeftRadius + arrowWidth / 2;
|
|
}else if (arrowPosition > YBRectHeight(rect) - bottomLeftRadius - arrowWidth / 2) {
|
|
arrowPosition = YBRectHeight(rect) - bottomLeftRadius - arrowWidth / 2;
|
|
}
|
|
[bezierPath moveToPoint:CGPointMake(arrowHeight + YBRectX(rect), arrowPosition + arrowWidth / 2)];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowPosition)];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowHeight + YBRectX(rect), arrowPosition - arrowWidth / 2)];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowHeight + YBRectX(rect), topLeftRadius + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(arrowHeight + bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
|
|
|
|
}else if (arrowDirection == YBPopupMenuArrowDirectionRight) {
|
|
topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect),topLeftRadius + YBRectX(rect));
|
|
topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect) - arrowHeight, topRightRadius + YBRectX(rect));
|
|
bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
|
|
bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect) - arrowHeight, YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
|
|
if (arrowPosition < topRightRadius + arrowWidth / 2) {
|
|
arrowPosition = topRightRadius + arrowWidth / 2;
|
|
}else if (arrowPosition > YBRectHeight(rect) - bottomRightRadius - arrowWidth / 2) {
|
|
arrowPosition = YBRectHeight(rect) - bottomRightRadius - arrowWidth / 2;
|
|
}
|
|
[bezierPath moveToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), arrowPosition - arrowWidth / 2)];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), arrowPosition)];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), arrowPosition + arrowWidth / 2)];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect) - arrowHeight, YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
|
|
|
|
}else if (arrowDirection == YBPopupMenuArrowDirectionNone) {
|
|
topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect), topLeftRadius + YBRectX(rect));
|
|
topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
|
|
bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
|
|
bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
|
|
[bezierPath moveToPoint:CGPointMake(topLeftRadius + YBRectX(rect), YBRectX(rect))];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
|
|
[bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
|
|
[bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
|
|
}
|
|
|
|
[bezierPath closePath];
|
|
return bezierPath;
|
|
}
|
|
|
|
@end
|