I have the following UI in storyboard.
The structure is as follows
- Parent (
UIView
)- ThinBlock (
UIView
) (green one)- MusicStaffView (
UIView
) (musical notation, actually it'sUILabel
as loaded via through setting via custom class)
- MusicStaffView (
- ThinBlock (
My goal is to place another UILabel
which contains an individual musical note, or say a string with length 1 on top of specific location when the music plays.
The end result should be like this.
The setup as you see above is based on auto-layout. My understand is that if I need to manually place something individually on top, thus I don't need auto-layout enabled for that element.
So it seems that I need to find absolute position of individual character inside UILabel
, create UILabel
on the fly, then add it as a child of UIViewController
's view
. But I can't achieve that, it always placed on the top left no matter what.
Here is the code I use to get the target string, its absolute position, creation of UILabel
and place it at that position on the fly.
// calculate prefix size
NSRange range = NSMakeRange(2, 1);
NSString *prefix = [self.leftPattern.scoreLabel.text substringToIndex:range.location];
NSDictionary *attributes = @{NSFontAttributeName: self.leftPattern.scoreLabel.font};
CGSize size = [prefix sizeWithAttributes:attributes];
CGPoint p = CGPointMake(size.width, 0);
NSLog(@"prefix width: %f",p.x);
NSLog(@"prefix height: %f",p.y);
// calculate size of target string
NSString *targetString = [self.leftPattern.scoreLabel.text substringWithRange:range];
CGSize targetSize = [targetString sizeWithAttributes:attributes];
NSLog(@"Old point %@", NSStringFromCGPoint(self.leftPattern.frame.origin));
// find absolute point to place our UILabel later
CGPoint localPoint = self.leftPattern.scoreLabel.frame.origin;
CGPoint absolutePoint = [self.leftPattern.scoreLabel convertPoint:localPoint toView:[self.view window]];
NSLog(@"Absolute point %@", NSStringFromCGPoint(absolutePoint));
// create UILabel to place at calculated absolute point
UILabel *newLabel = [[UILabel alloc]initWithFrame:CGRectMake(absolutePoint.x + p.x, absolutePoint.y - 10, targetSize.width, targetSize.height)];
NSLog(@"newLabel frame: %@", NSStringFromCGRect(newLabel.frame));
newLabel.text = targetString;
newLabel.font = self.leftPattern.scoreLabel.font;
newLabel.numberOfLines = 1;
newLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines; // or UIBaselineAdjustmentAlignCenters, or UIBaselineAdjustmentNone
newLabel.adjustsFontSizeToFitWidth = NO;
newLabel.clipsToBounds = YES;
newLabel.backgroundColor = [UIColor clearColor];
newLabel.textColor = [UIColor redColor];
newLabel.textAlignment = NSTextAlignmentCenter;
[newLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:newLabel];
[self.view layoutIfNeeded];
What I got from NSLog()
is as follows
prefix is |\
prefix width: 18.780000
prefix height: 0.000000
Old point {8, 0}
Absolute point {49.333333333333314, 101.33333333333331}
newLabel frame: {{68.113333333333316, 101.33333333333331}, {16, 43}}
Also, it gets worse and more difficult when I rotate the device into landscape, UILabel
is aligned center thus introduce space in front in which I don't know how to calculate its space width too.
Solution or suggestion to solve this will be really appreciated!