Reputation: 1173
I want to make a tooltip like UILabel with some custom code. I managed to add a triangle to the UILabel, but since it's out of the bound (or frame) of the UILabel itself. It's not drawing on the screen.
Here's my approach:
- (void) addTriangleTipToLayer: (CALayer *) targetLayer{
[targetLayer setBackgroundColor: [UIColor whiteColor].CGColor];
CGPoint startPoint = CGPointMake(0, targetLayer.frame.size.height);
CGPoint endPoint = CGPointMake(15, targetLayer.frame.size.height);
UIBezierPath *trianglePath = [UIBezierPath bezierPath];
CGFloat middleX = (startPoint.x + endPoint.x) / 2;
CGFloat middleY = 7.5 * tan(M_PI / 3);
CGPoint middlePoint = CGPointMake(middleX, -middleY);
[trianglePath moveToPoint:startPoint];
[trianglePath addLineToPoint:middlePoint];
[trianglePath addLineToPoint:endPoint];
[trianglePath closePath];
CGAffineTransform rotate = CGAffineTransformMakeRotation(180);
[trianglePath applyTransform:rotate];
CAShapeLayer *triangleLayer = [CAShapeLayer layer];
[triangleLayer setFillColor: [UIColor whiteColor].CGColor];
[triangleLayer setPath:trianglePath.CGPath];
[targetLayer addSublayer:triangleLayer];
}
I also convert the label into a image content for the use as a Google Map Marker Icon. here's the other things I did to this UILabel.
UILabel *klabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 20)];
[klabel setFont: [UIFont fontWithName:@"Roboto-Light" size:9]];
[klabel setText: @"Tower"];
// here I apply the add triangle function to the uilabel.layer
[self addTriangleTipToLayer:klabel.layer];
//set the label to fit text content before rendered as a image
[klabel sizeToFit];
//convert the uilabel to image content
UIGraphicsBeginImageContextWithOptions(klabel.bounds.size, NO, [[UIScreen mainScreen] scale]);
[klabel.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * kicon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// the rest of code is just use the image content as marker icon on google map.
kaliaMarker = [[GMSMarker alloc] init];
kaliaMarker.tappable = NO;
kaliaMarker.position = CLLocationCoordinate2DMake(21.283652, -157.836971);
kaliaMarker.infoWindowAnchor = CGPointMake(0.5, 0.5);
kaliaMarker.icon = kicon;
kaliaMarker.map = self.mapView;
the targetLayer
is the myLabel.layer
, which is where I add my triangle to. the problem is the middleY
is -12.4
from the calculation, and I guess it fell out of the visible bound/frame of my UILabel and you just can't see it.
I'm wondering what should I do or what is the proper approach to increase the visible part of my UILabel to show this little triangle.
Thanks for you guys' help!.
P.S. it should look like this.
But it looks like this. if I rotate the path by 90 degree, I can see the half triangle, it's there of course. So for 180 degree, the entire triangle is out of bounds which can not be seen..
Upvotes: 2
Views: 3058
Reputation: 1173
I found problem in my code.
//convert the uilabel to image content
UIGraphicsBeginImageContextWithOptions(klabel.bounds.size, NO, [[UIScreen mainScreen] scale]);
did not include enough space for the arrow layer added to the uilabel. Also I add the triangle in the wrong way. The correct code should be:
[targetLayer setBackgroundColor: [UIColor whiteColor].CGColor];
CGFloat side = targetLayer.frame.size.height;
CGPoint startPoint = CGPointMake(targetLayer.frame.size.width / 2 - side / 2, side);
CGPoint endPoint = CGPointMake(targetLayer.frame.size.width / 2 + side / 2, side);
UIBezierPath *trianglePath = [UIBezierPath bezierPath];
CGFloat middleX = targetLayer.frame.size.width / 2;
CGFloat middleY = (side / 2) * tan(M_PI / 3) + side;
CGPoint middlePoint = CGPointMake(middleX, middleY);
[trianglePath moveToPoint:startPoint];
[trianglePath addLineToPoint:middlePoint];
[trianglePath addLineToPoint:endPoint];
[trianglePath closePath];
CAShapeLayer *triangleLayer = [CAShapeLayer layer];
[triangleLayer setFillColor: [UIColor whiteColor].CGColor];
[triangleLayer setPath:trianglePath.CGPath];
[targetLayer addSublayer:triangleLayer];
this will add equilateral triangle center to the label itself. then the code to draw the convert to images should be:
//convert the uilabel to image content
UIGraphicsBeginImageContextWithOptions(CGRectMake(self.klabel.bounds.size.width, 2 * self.klabel.bounds.size.height), NO, [[UIScreen mainScreen] scale]);
thanks for you guys' help!
Upvotes: 1
Reputation: 104082
This slightly modified code works fine. I changed the argument of the method to UIView so that I could access its background color to make the triangle that same color, and made the y value of the triangle's point proportional to the height of the view.
- (void) addTriangleTipToLayer: (UIView *) view{
CALayer *targetLayer = view.layer;
[targetLayer setBackgroundColor: [UIColor whiteColor].CGColor];
CGPoint startPoint = CGPointMake(0, targetLayer.frame.size.height);
CGPoint endPoint = CGPointMake(15, targetLayer.frame.size.height);
UIBezierPath *trianglePath = [UIBezierPath bezierPath];
CGFloat middleX = (startPoint.x + endPoint.x) / 2;
CGFloat middleY = targetLayer.frame.size.height * 1.8;
CGPoint middlePoint = CGPointMake(middleX, middleY);
[trianglePath moveToPoint:startPoint];
[trianglePath addLineToPoint:middlePoint];
[trianglePath addLineToPoint:endPoint];
[trianglePath closePath];
CAShapeLayer *triangleLayer = [CAShapeLayer layer];
[triangleLayer setFillColor: view.backgroundColor.CGColor];
[triangleLayer setPath:trianglePath.CGPath];
[targetLayer addSublayer:triangleLayer];
}
Upvotes: 2
Reputation: 107211
Actually your arrow is there, your background is white color so, you can't see that. Set a fill color to your layer.
[triangleLayer setFillColor:[[UIColor redColor] CGColor]];
Upvotes: 2