How to make change the arrow direction of this UIBezierPath

1.1k views Asked by At

I have the following code which draws a rounded rect with a small caret arrow on the top. I want to be able to create a method that either draws the arrow at the top, left, right, or bottom depending on what I specify (I'll likely pass in an enum typedef).

Here is what my code generates right now:

enter image description here

Can anyone help me make this code more dynamic/flexible so I can accomplish this?

        CGContextBeginPath(context);
        CGContextMoveToPoint(context, kBubbleBorderRadius + 0.5f, kCaretHeight + 0.5f);
        CGContextAddLineToPoint(context, round(currentFrame.size.width / 2.0f - (kCaretHeight * 2.0) / 2.0f) + 0.5f, kCaretHeight + 0.5f);
        CGContextAddLineToPoint(context, round(currentFrame.size.width / 2.0f) + 0.5f, 0.5f);
        CGContextAddLineToPoint(context, round(currentFrame.size.width / 2.0f + (kCaretHeight * 2.0) / 2.0f) + 0.5f, kCaretHeight + 0.5f);
        CGContextAddArcToPoint(context, currentFrame.size.width - 0.5f, kCaretHeight + 0.5f, currentFrame.size.width- 0.5f, currentFrame.size.height - 0.5f, kBubbleBorderRadius);
        CGContextAddArcToPoint(context, currentFrame.size.width - 0.5f, currentFrame.size.height - 0.5f, round(currentFrame.size.width / 2.0f + (kCaretHeight * 2.0) / 2.0f) + 0.5f, currentFrame.size.height - 0.5f, kBubbleBorderRadius);
        CGContextAddArcToPoint(context, 0.5f, currentFrame.size.height - 0.5f, 0.5f, kCaretHeight + 0.5f, kBubbleBorderRadius);
        CGContextAddArcToPoint(context, 0.5f, kCaretHeight + 0.5f, currentFrame.size.width - 0.5f, kCaretHeight + 0.5f, kBubbleBorderRadius);
        CGContextClosePath(context);
        CGContextDrawPath(context, kCGPathFill);
1

There are 1 answers

0
Injectios On BEST ANSWER

I can give you point to start from. First, I would separate rectangle and arrow:

drawing simple rectangle:

const CGFloat kRectangleOffset = 5; // This is offset to have some space for arrow

// Draw simple rectangle in DrawRect method
    CGRect frame = CGRectMake(0+kRectangleOffset,
                              0+kRectangleOffset,
                              rect.size.width-kRectangleOffset*2,
                              rect.size.height-kRectangleOffset*2);

    UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: frame];
    [UIColor.grayColor setFill];
    [rectanglePath fill];

Add as subview f.e:

- (void)viewDidLoad {
    [super viewDidLoad];

    BoxView *box = [[BoxView alloc] initWithFrame:CGRectMake(100, 100, 200, 80)];
    box.backgroundColor = [UIColor redColor]; // I specially set red color to see it's full surface...
    [self.view addSubview:box];
}

enter image description here

Then simple arrow drawing on the centre of rectangle

const CGFloat kArrowWidth = 10;

  // Draw Bezier arrow on top consists of 3 points 
    UIBezierPath* bezierPathTop = UIBezierPath.bezierPath;
    [bezierPathTop moveToPoint: CGPointMake(rect.size.width/2-kArrowWidth/2, kRectangleOffset)];
    [bezierPathTop addLineToPoint: CGPointMake(rect.size.width/2+kArrowWidth/2, kRectangleOffset)];
    [bezierPathTop addLineToPoint: CGPointMake(rect.size.width/2, 0)];
    [UIColor.blueColor setFill];
    [bezierPathTop fill];

enter image description here

And finally same arrow but with different points location

UIBezierPath* bezierPathLeft = UIBezierPath.bezierPath;
[bezierPathLeft moveToPoint: CGPointMake(kRectangleOffset, rect.size.height/2-kArrowWidth/2)];
[bezierPathLeft addLineToPoint: CGPointMake(kRectangleOffset, rect.size.height/2+kArrowWidth/2)];
[bezierPathLeft addLineToPoint: CGPointMake(0, rect.size.height/2)];
[UIColor.blueColor setFill];
[bezierPathLeft fill];

enter image description here

You need to draw just one arrow for sure based on let's say arrow direction enum. I hope you can go further with this sample