YBPopupMenuPath.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // YBPopupMenuPath.m
  3. // YBPopupMenu
  4. //
  5. // Created by lyb on 2017/5/9.
  6. // Copyright © 2017年 lyb. All rights reserved.
  7. //
  8. #import "YBPopupMenuPath.h"
  9. #import "YBRectConst.h"
  10. @implementation YBPopupMenuPath
  11. + (CAShapeLayer *)yb_maskLayerWithRect:(CGRect)rect
  12. rectCorner:(UIRectCorner)rectCorner
  13. cornerRadius:(CGFloat)cornerRadius
  14. arrowWidth:(CGFloat)arrowWidth
  15. arrowHeight:(CGFloat)arrowHeight
  16. arrowPosition:(CGFloat)arrowPosition
  17. arrowDirection:(YBPopupMenuArrowDirection)arrowDirection
  18. {
  19. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  20. 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;
  21. return shapeLayer;
  22. }
  23. + (UIBezierPath *)yb_bezierPathWithRect:(CGRect)rect
  24. rectCorner:(UIRectCorner)rectCorner
  25. cornerRadius:(CGFloat)cornerRadius
  26. borderWidth:(CGFloat)borderWidth
  27. borderColor:(UIColor *)borderColor
  28. backgroundColor:(UIColor *)backgroundColor
  29. arrowWidth:(CGFloat)arrowWidth
  30. arrowHeight:(CGFloat)arrowHeight
  31. arrowPosition:(CGFloat)arrowPosition
  32. arrowDirection:(YBPopupMenuArrowDirection)arrowDirection
  33. {
  34. UIBezierPath *bezierPath = [UIBezierPath bezierPath];
  35. if (borderColor) {
  36. [borderColor setStroke];
  37. }
  38. if (backgroundColor) {
  39. [backgroundColor setFill];
  40. }
  41. bezierPath.lineWidth = borderWidth;
  42. rect = CGRectMake(borderWidth / 2, borderWidth / 2, YBRectWidth(rect) - borderWidth, YBRectHeight(rect) - borderWidth);
  43. CGFloat topRightRadius = 0,topLeftRadius = 0,bottomRightRadius = 0,bottomLeftRadius = 0;
  44. CGPoint topRightArcCenter,topLeftArcCenter,bottomRightArcCenter,bottomLeftArcCenter;
  45. if (rectCorner & UIRectCornerTopLeft) {
  46. topLeftRadius = cornerRadius;
  47. }
  48. if (rectCorner & UIRectCornerTopRight) {
  49. topRightRadius = cornerRadius;
  50. }
  51. if (rectCorner & UIRectCornerBottomLeft) {
  52. bottomLeftRadius = cornerRadius;
  53. }
  54. if (rectCorner & UIRectCornerBottomRight) {
  55. bottomRightRadius = cornerRadius;
  56. }
  57. if (arrowDirection == YBPopupMenuArrowDirectionTop) {
  58. topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect));
  59. topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), arrowHeight + topRightRadius + YBRectX(rect));
  60. bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
  61. bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
  62. if (arrowPosition < topLeftRadius + arrowWidth / 2) {
  63. arrowPosition = topLeftRadius + arrowWidth / 2;
  64. }else if (arrowPosition > YBRectWidth(rect) - topRightRadius - arrowWidth / 2) {
  65. arrowPosition = YBRectWidth(rect) - topRightRadius - arrowWidth / 2;
  66. }
  67. [bezierPath moveToPoint:CGPointMake(arrowPosition - arrowWidth / 2, arrowHeight + YBRectX(rect))];
  68. [bezierPath addLineToPoint:CGPointMake(arrowPosition, YBRectTop(rect) + YBRectX(rect))];
  69. [bezierPath addLineToPoint:CGPointMake(arrowPosition + arrowWidth / 2, arrowHeight + YBRectX(rect))];
  70. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, arrowHeight + YBRectX(rect))];
  71. [bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
  72. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
  73. [bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
  74. [bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
  75. [bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
  76. [bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
  77. [bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
  78. }else if (arrowDirection == YBPopupMenuArrowDirectionBottom) {
  79. topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect),topLeftRadius + YBRectX(rect));
  80. topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
  81. bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect) - arrowHeight);
  82. bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect) - arrowHeight);
  83. if (arrowPosition < bottomLeftRadius + arrowWidth / 2) {
  84. arrowPosition = bottomLeftRadius + arrowWidth / 2;
  85. }else if (arrowPosition > YBRectWidth(rect) - bottomRightRadius - arrowWidth / 2) {
  86. arrowPosition = YBRectWidth(rect) - bottomRightRadius - arrowWidth / 2;
  87. }
  88. [bezierPath moveToPoint:CGPointMake(arrowPosition + arrowWidth / 2, YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
  89. [bezierPath addLineToPoint:CGPointMake(arrowPosition, YBRectHeight(rect) + YBRectX(rect))];
  90. [bezierPath addLineToPoint:CGPointMake(arrowPosition - arrowWidth / 2, YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
  91. [bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - arrowHeight + YBRectX(rect))];
  92. [bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
  93. [bezierPath addLineToPoint:CGPointMake(YBRectX(rect), topLeftRadius + YBRectX(rect))];
  94. [bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
  95. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), YBRectX(rect))];
  96. [bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
  97. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect) - arrowHeight)];
  98. [bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
  99. }else if (arrowDirection == YBPopupMenuArrowDirectionLeft) {
  100. topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect) + arrowHeight,topLeftRadius + YBRectX(rect));
  101. topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
  102. bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect) + arrowHeight, YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
  103. bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
  104. if (arrowPosition < topLeftRadius + arrowWidth / 2) {
  105. arrowPosition = topLeftRadius + arrowWidth / 2;
  106. }else if (arrowPosition > YBRectHeight(rect) - bottomLeftRadius - arrowWidth / 2) {
  107. arrowPosition = YBRectHeight(rect) - bottomLeftRadius - arrowWidth / 2;
  108. }
  109. [bezierPath moveToPoint:CGPointMake(arrowHeight + YBRectX(rect), arrowPosition + arrowWidth / 2)];
  110. [bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowPosition)];
  111. [bezierPath addLineToPoint:CGPointMake(arrowHeight + YBRectX(rect), arrowPosition - arrowWidth / 2)];
  112. [bezierPath addLineToPoint:CGPointMake(arrowHeight + YBRectX(rect), topLeftRadius + YBRectX(rect))];
  113. [bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
  114. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, YBRectX(rect))];
  115. [bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
  116. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
  117. [bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
  118. [bezierPath addLineToPoint:CGPointMake(arrowHeight + bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
  119. [bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
  120. }else if (arrowDirection == YBPopupMenuArrowDirectionRight) {
  121. topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect),topLeftRadius + YBRectX(rect));
  122. topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect) - arrowHeight, topRightRadius + YBRectX(rect));
  123. bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
  124. bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect) - arrowHeight, YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
  125. if (arrowPosition < topRightRadius + arrowWidth / 2) {
  126. arrowPosition = topRightRadius + arrowWidth / 2;
  127. }else if (arrowPosition > YBRectHeight(rect) - bottomRightRadius - arrowWidth / 2) {
  128. arrowPosition = YBRectHeight(rect) - bottomRightRadius - arrowWidth / 2;
  129. }
  130. [bezierPath moveToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), arrowPosition - arrowWidth / 2)];
  131. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), arrowPosition)];
  132. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), arrowPosition + arrowWidth / 2)];
  133. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - arrowHeight + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
  134. [bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
  135. [bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
  136. [bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
  137. [bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
  138. [bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
  139. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect) - arrowHeight, YBRectX(rect))];
  140. [bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
  141. }else if (arrowDirection == YBPopupMenuArrowDirectionNone) {
  142. topLeftArcCenter = CGPointMake(topLeftRadius + YBRectX(rect), topLeftRadius + YBRectX(rect));
  143. topRightArcCenter = CGPointMake(YBRectWidth(rect) - topRightRadius + YBRectX(rect), topRightRadius + YBRectX(rect));
  144. bottomLeftArcCenter = CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) - bottomLeftRadius + YBRectX(rect));
  145. bottomRightArcCenter = CGPointMake(YBRectWidth(rect) - bottomRightRadius + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius + YBRectX(rect));
  146. [bezierPath moveToPoint:CGPointMake(topLeftRadius + YBRectX(rect), YBRectX(rect))];
  147. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) - topRightRadius, YBRectX(rect))];
  148. [bezierPath addArcWithCenter:topRightArcCenter radius:topRightRadius startAngle:M_PI * 3 / 2 endAngle:2 * M_PI clockwise:YES];
  149. [bezierPath addLineToPoint:CGPointMake(YBRectWidth(rect) + YBRectX(rect), YBRectHeight(rect) - bottomRightRadius - YBRectX(rect))];
  150. [bezierPath addArcWithCenter:bottomRightArcCenter radius:bottomRightRadius startAngle:0 endAngle:M_PI_2 clockwise:YES];
  151. [bezierPath addLineToPoint:CGPointMake(bottomLeftRadius + YBRectX(rect), YBRectHeight(rect) + YBRectX(rect))];
  152. [bezierPath addArcWithCenter:bottomLeftArcCenter radius:bottomLeftRadius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
  153. [bezierPath addLineToPoint:CGPointMake(YBRectX(rect), arrowHeight + topLeftRadius + YBRectX(rect))];
  154. [bezierPath addArcWithCenter:topLeftArcCenter radius:topLeftRadius startAngle:M_PI endAngle:M_PI * 3 / 2 clockwise:YES];
  155. }
  156. [bezierPath closePath];
  157. return bezierPath;
  158. }
  159. @end