I have a reusable UITableViewCell as part of my storyboard, where I need to sizeToFit after the text has been set. To achieve this I am performing the sizeToFit in the layoutSubviews method of my cell class.
But the problem is that I'm not seeing any updates, I've tried setting needsDisplay/Layout but I can't see any updates until the cell needs to be completely re-rendered (either when I scroll down and up or when I begin & end updates to the tableView).
I've managed to resolve this by creating a class for the UILabel and then performing the needs inside layoutSubviews for my subclassed UILabel.
If you are using autolayout then try setting preferredMaxLayoutWidth property of label in your cell's layoutSubviews method. You need to call [super layoutSubviews] again after setting that property.
- (void)layoutSubviews
{
[super layoutSubviews];
// Make sure that label's text is set by now
self.label.preferredMaxLayoutWidth = self.label.frame.size.width;
[super layoutSubviews];
}
Related
I have custom UIView with 2 multiline labels. Sometimes I need to hide this view so I set hidden = YES and height constraint to 0.
I am doing it this way but I'm not quite sure if I can change my constraints in my custom UIViews' layoutSubviews.
- (void)layoutSubviews {
[super layoutSubviews];
if (!self.hidden) {
self.heightConstraint.constant = 15 + self.titleLabel.frame.size.height + 4 + self.bodyLabel.frame.size.height + 15;
} else {
self.heightConstraint.constant = 0;
}
}
I know that layout is not one-way street process and layoutSubviews can cause updateConstraints and vice versa.
Is it safe to change constraints of view itself in layoutSubviews?
layoutSubviews is called after the updateConstraints method has done its job. If you change constraints after that, you're gonna have to call [super layoutSubviews] again. The correct place to modify constraints is in the updateConstraints method, but in your case you can simply make your changes outside the layoutSubviews method and then call setNeedsLayout after you're done.
You need setNeedsLayout method. Example:
self.view.setNeedsLayout()
When I use a subclass of UIView and put it on the storyboard with some constraints,i check its frame in awakeFromNib() or didMoveToWindow(). The result is not correct cause the constraints are not applied yet.
Is there any callback to inform me that the constraints are applied? So after that i can do sth with the correct frame.
When awakeFromNib viewDidLoad or didMoveToWindow is called, layout is not completed yet. You have to use viewDidLayoutSubviewsof a viewController. This method will be called after applying constraints and completing layout.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
}
I have a nib with a table cell, and within that table cell I have a UILabel. I want to make that label sizeToFit which means I have to do:
- (void)viewDidLoad {
[self sizeToFit];
}
However my label doesn't have any code, just an outlet to a variable in my controller, so there's nowhere I can put that code to effect the label.
I attempted making a sub class of UILabel (fitUILabel : UILabel) and then I clicked on the label in the nib and set its class to fitUILabel, however it does not seem to run.
In my controller right before the return statement in cellForRowAtIndexPath I tried putting
[cell.myLabelOutletVariable sizeToFit]
And this seems to work, however it only works on the recycled rows and not the labels contained in the initial cells of my table. This also seems to cause my text to flow right out of the cells and overlap onto others, however it does align it to the top which is what I wanted.
I assume you mean that your nib contains a UITableViewCell as a top-level object, and the table view cell has a UILabel subview.
The viewDidLoad method is defined on UIViewController, and UITableViewCell doesn't inherit from UIViewController.
UITableViewCell is a subclass of UIView. The proper place for a view to adjust the frames of its subviews is in its layoutSubviews method. You need to make a subclass of UITableViewCell, and set that as the custom class of the cell in your nib. Then, in your subclass, define this method:
- (void)layoutSubviews {
[self.label sizeToFit];
}
In your table view data source's tableView:cellForRowAtIndexPath: method, you may want to send setNeedsLayout to the cell after setting the text of the label. This will ensure that the cell receives layoutSubviews again, if it's being reused.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = ...;
cell.customLabel.text = [self labelTextForIndexPath:indexPath];
[cell setNeedsLayout];
return cell;
}
Alternatively, you could make a UILabel subclass, like this:
#implementation MyLabel
- (void)layoutSubviews {
[self sizeToFit];
}
- (void)setText:(NSString *)text {
[super setText:text];
[self setNeedsLayout];
}
#end
and then set MyLabel as the custom class of the label in your nib. But having a view set its own frame in layoutSubviews seems a little fishy to me, so I usually avoid it.
You should put your code for size the Label in Table view's Delegate Method CellForRowAtIndexPath and not in viewDidLoad.
If your Label is in Table View Cell.
You may rewrite the -(void) awakeFromNib method for initializing the Label.
I'm re-writting an app under IOS6 with autolayout but have problems accessing the size of a subclass of UIView
#property (weak, nonatomic) IBOutlet MyView *myView1;
in
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"myView1: %#",self.myView1);
}
The size of the UIView is fully defined in the StoryBoard but comes out as zero when I run the code. Is this todo with auto layout or is the subview simply not defined yet? Am I doing something basically wrong here?
Just found one possible answer here. Running the methods
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
forces a calculation of UIViews dimensions causing the expected values to appear in the log and also be known unto the UIView subclass itself.
I just printed the frame of a subview.
It was 0 in viewDidLoad.
It had a non-zero value inside the viewDidLayoutSubviews callback.
Inside the viewDidLoad you should only expect that the value of the viewcontroller's view to be non-zero. Inside viewDidLoad is actually where sometimes you add subviews and stuff. So it's not correct to expect the frame to get calculated in the very callback that you're settings constraints for it.
Basically what needs to be understood is that first a viewController is drawn, then as it goes through its life cycle events, its subviews will get laid out
I have a custom class that's a subclass of UIView. In the storyboard I set a UIView's class to the custom class. The view in the storyboard has a height constraint so that I can change the height programmatically. (I know it's not the only way, but I think it's the easiest way.)
I want to perform some code in the custom class every time the view's height changes.
I tried the following:
- (void)setFrame:(CGRect)frame {
[super setFrame:frame};
NSLog(#"Frame did change");
}
But this method only runs on startup, not when it's (self) height was changed. How can I perform code anytime it's frame is changed?
Just override layoutSubviews method in your custom view class
- (void)layoutSubviews
{
[super layoutSubviews];
NSLog(#"Frame did change");
}