I am desperately trying to stick one of my UILabels to the right edge of it's superview while the label's width is variable (it's a time so the thing is getting bigger and should be expanding to the left, this is done using sizeToFit inside of the label when text is set).
So far I have tried loads of things but closest I got with:
_elapsedTimeRightConstraint = [NSLayoutConstraint constraintWithItem:_elapsedTimeView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:-150];
While the label is initially set to 150px width. But when I modify the constant, it all goes to hell.
_elapsedTimeRightConstraint.constant = (_elapsedTimeView.frame.size.width * -1);
[self layoutIfNeeded];
So my question is, how do I align trailing edges of a view and it's superview (so it sticks to the right) when the width of the subview is constantly changing. I have been using FLKAutoLayout
elsewhere in the project so if this can be done this framework easily than great, but basic autolayout solution would be amazing too!!!
To add a subview to another view, call the addSubview(_:) method on the superview. You may add any number of subviews to a view, and sibling views may overlap each other without any issues in iOS.
If you need a quick way to get hold of a view inside a complicated view hierarchy, you're looking for viewWithTag() – give it the tag to find and a view to search from, and this method will search all subviews, and all sub-subviews, and so on, until it finds a view with the matching tag number.
UIView can be defined as an object by using which we can create and manage the rectangular area on the screen. We can have any number of views inside a view to create a hierarchical structure of the UIViews. The UIView is managed by using the methods and properties defined in the UIView class that inherits UIKit.
First, make sure that translatesAutoresizingMaskIntoConstraints
is set to NO
, if you are creating the label programmatically.
The first constraint you need is "label.trailing = superview.trailing".
[NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f]
This will pin the right edge (on left-to-right languages) of the label on the right edge of the superview.
You will now need a constraint for the Y
position.
In my test, I have vertically centred the label with the following constraint:
[NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f]
Now comes the trick!
Every time you change the text on the label, you need to recalculate the frames with AutoLayout.
[superview setNeedsLayout];
[superview layoutIfNeeded];
AutoLayout will:
1) Ask the label of its new size (based on its text).
2) Adjust the size of the label.
3) Pin the trailing edge of the label to the trailing edge of the superview.
Further research
The issue with UILabel is that when you're using AutoLayout and you set text, its intrinsicContentSize
changes, but it doesn't trigger a layout update.
A way to enforce this without subclassing UILabel is to use Objective-C runtime.
@interface UILabel (AutoLayout)
- (void)swz_setText:(NSString*)text;
@end
@implementation UILabel (AutoLayout)
+ (void)load
{
NSLog(@"Swizzling [UILabel setFont:]...");
Method oldMethod = class_getInstanceMethod(self, @selector(setText:));
Method newMethod = class_getInstanceMethod(self, @selector(swz_setText:));
method_exchangeImplementations(oldMethod, newMethod);
}
- (void)swz_setText:(NSString*)text
{
if (![text isEqualToString:self.text]) {
[self setNeedsLayout];
}
[self swz_setText:text]; //This now points to "setText:" - not a mistake!
}
@end
In this category, I'm "enhancing" setText:
implementation by calling setNeedsLayout
if the text changes.
Now you just need to invoke layoutIfNeeded
on the superview to recalculate/realign the label frame.
Click here for the playground (Swift 2.0 - Xcode 7) where I've tested my code.
I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With