Width of contentView in UITableViewCell is different for each cell - ios

In an UITableViewController defined in a Storyboard with Auto Layout enabled, a UITableViewCell subclass is created programatically (no IB prototype cell) and sets constraints through updateConstraints using PureLayout.
For some reason, the table view has each contentView with a different width, instead of using the const width of UITableView.
Here's the init and updateConstraints method of UITableViewCell subclass -
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
_nameLabel = [GTPaddedLabel newAutoLayoutView];
_nameLabel.font = [BQFontUtil standardFontSize:StandardFontSize1a bold:YES italic:NO];
_nameLabel.textColor = [UIColor blackColor];
_drugType = [UILabel newAutoLayoutView];
_drugType.font = [BQFontUtil standardFontSize:StandardFontSize0 bold:NO italic:NO];
_drugType.textColor = [UIColor darkGrayColor];
_drugType.textAlignment = NSTextAlignmentRight;
_genericsLabel = [UILabel newAutoLayoutView];
_genericsLabel.font = [BQFontUtil standardFontSize:StandardFontSize0 bold:NO italic:NO];
_genericsLabel.textColor = [UIColor darkGrayColor];
_regimen = [UILabel newAutoLayoutView];
_regimen.font = [BQFontUtil standardFontSize:StandardFontSize0 bold:NO italic:NO];
_regimen.textColor = [UIColor darkGrayColor];
[self.contentView addSubview:_nameLabel];
[self.contentView addSubview:_drugType];
[self.contentView addSubview:_genericsLabel];
[self.contentView addSubview:_regimen];
self.contentView.backgroundColor = [UIColor redColor];
}
return self;
}
- (void)updateConstraints {
if (!constraintsCreated) {
// [self.contentView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[UIView autoSetPriority:UILayoutPriorityRequired forConstraints:^{
[_nameLabel autoSetContentCompressionResistancePriorityForAxis:ALAxisVertical];
}];
[_nameLabel autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(8, 8, 0, 8) excludingEdge:ALEdgeBottom];
[_genericsLabel autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:16];
[_genericsLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_nameLabel withOffset:4];
[_genericsLabel autoSetDimension:ALDimensionHeight toSize:21];
[_drugType autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:16];
[_drugType autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_nameLabel withOffset:4];
[_drugType autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:_genericsLabel withOffset:8];
[_drugType autoSetDimension:ALDimensionHeight toSize:21];
[_regimen autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_genericsLabel withOffset:2];
[_regimen autoSetDimension:ALDimensionHeight toSize:21];
[_regimen autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:16];
[_regimen autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:16];
[_regimen autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:8];
constraintsCreated = YES;
}
[super updateConstraints];
}
Why does contentView (brown color) doesn't have the same width as the table view?

Maybe that's a workaround, it works well when I'm constraining contentView's width to cell's width -
- (void)updateConstraints {
if (!constraintsCreated) {
[self.contentView autoSetDimension:ALDimensionWidth toSize:self.frame.size.width];
...
}
}

Related

Cannot select/edit text in UITextView within UIScrollView

I have setup my UIScrollView with subviews like so using Masonry:
- (void)setupViews {
self.view.backgroundColor = [UIColor Background];
self.scrollView = [UIScrollView new];
self.scrollView.alwaysBounceVertical = YES;
[self.view addSubview:self.scrollView];
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
self.contentView = [UIView new];
[self.scrollView addSubview:self.contentView];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.scrollView);
make.left.and.right.equalTo(self.view);
}];
self.imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.imageButton sd_setImageWithURL:[NSURL URLWithString:self.card.cardImageURL] forState:UIControlStateNormal];
[self.imageButton.imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.contentView addSubview:self.imageButton];
[self.imageButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.and.right.equalTo(self.contentView);
make.height.equalTo(self.imageButton.mas_width).multipliedBy(3/4.0);
}];
self.textField = [UITextField new];
self.textField.backgroundColor = [UIColor whiteColor];
self.textField.font = kFontRegular(14);
self.textField.text = self.card.cardTitle;
[self.contentView addSubview:self.textField];
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).with.offset(8);
make.top.equalTo(self.imageButton.mas_bottom).with.offset(8);
make.right.equalTo(self.contentView).with.offset(-8);
make.height.equalTo(#(45));
}];
}
but it will not let me interact with the UITextField. what element here is preventing user interaction?
Your contentView's height will be zero. So it will never get some touch events. You should not use this constraint:
make.edges.equalTo(self.scrollView);
It will not get a correct value. Try to set top and height constraints for your contentView.
make.top.equalTo(#0);
make.height.equalTo(#700);

UIScrollView paging disabled after rotation

Following is my code for App Tour using UIScrollView with paging enabled using AutoLayout (Masonry) It works fine in Portrait but when I rotate paging gets disabled so it doesn't work in Landscape. Then it doesn't work in Portrait mode either. Can someone help what's wrong here?
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
self.scrollView = [UIScrollView new];
self.scrollView.backgroundColor = [UIColor clearColor];
self.scrollView.scrollEnabled = YES;
self.scrollView.pagingEnabled = YES;
self.scrollView.delegate = self;
self.scrollView.showsHorizontalScrollIndicator = NO;
[self.view addSubview:self.scrollView];
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
UIImageView *esImageview1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"CommonResources.bundle/page1"]];
esImageview1.contentMode = UIViewContentModeScaleAspectFit;
esImageview1.backgroundColor = [UIColor clearColor];
esImageview1.userInteractionEnabled = YES;
[self.scrollView addSubview:esImageview1];
[esImageview1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.bottom.equalTo(self.scrollView);
make.width.height.equalTo(self.view);
}];
UIImageView *esImageview2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"CommonResources.bundle/page2"]];
esImageview2.contentMode = UIViewContentModeScaleAspectFit;
esImageview2.backgroundColor = [UIColor clearColor];
esImageview2.userInteractionEnabled = YES;
[self.scrollView addSubview:esImageview2];
[esImageview2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(esImageview1.mas_right);
make.top.bottom.equalTo(self.scrollView);
make.width.height.equalTo(self.view);
}];
UIImageView *esImageview3 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"CommonResources.bundle/page3"]];
esImageview3.contentMode = UIViewContentModeScaleAspectFit;
esImageview3.backgroundColor = [UIColor clearColor];
esImageview3.userInteractionEnabled = YES;
[self.scrollView addSubview:esImageview3];
[esImageview3 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(esImageview2.mas_right);
make.top.bottom.equalTo(self.scrollView);
make.width.height.equalTo(self.view);
}];
self.pageControl = [UIPageControl new];
self.pageControl.numberOfPages = 3;
self.pageControl.currentPage = 0;
self.pageControl.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.pageControl];
[self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.height.equalTo(#40);
make.top.equalTo(self.view).with.offset(40);
}];
UILabel *titleLabel = [UILabel new];
titleLabel.text = #"App Tour";
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.font = [UIFont fontWithName:#"Helvetica-Light" size:16];
titleLabel.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:titleLabel];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.height.equalTo(#40);
make.top.equalTo(self.view).with.offset(20);
}];
UIButton *doneButton = [UIButton new];
[doneButton.titleLabel setFont:[UIFont fontWithName:#"Helvetica-Light" size:16]];
[doneButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[doneButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[doneButton setTitle:#"Done" forState:UIControlStateNormal];
[doneButton addTarget:self action:#selector(doneButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
doneButton.backgroundColor = [UIColor clearColor];
[self.view addSubview:doneButton];
[doneButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view);
make.height.equalTo(#40);
make.width.equalTo(#70);
make.top.equalTo(self.view).with.offset(20);
}];
}
- (void)doneButtonPressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width*self.pageControl.numberOfPages, self.view.frame.size.height);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
I'm guessing its getting covered up by another view or something similar to that. Try subclassing the UIScrollView and implementing the following method to check if its responding to your touches at all.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"OMG TOUCHES WORK, NOW WHAT?");
}
You can easily check if it was getting covered up by forcing it to be in front. Call this line of code in the callback for rotation in the UIViewController containing the UIScrollView. It should fix the problem. You may have to subclass the UIView for the controller and put this method in the didLayoutSubviews method instead, not quite sure, depends on your implementation.
[self.view bringSubViewToFront:self.scrollView];
Also check the frame and bounds before and after rotation and see if anything is out of place looking
I just wanted to reset Scrollview's contentsize in didRotateFromInterfaceOrientation delegate. Not sure why though because when I rotate, videDidLayoutSubview already gets called where I am already reseting content size.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width*self.pageControl.numberOfPages, self.view.frame.size.height);
}

Why is my TableView cell larger (higher) than its contents? (using autolayout)

This is driving me crazy. I have a tableview with, in each cell, a simple UILabel at the top and a line of images underneath. Like this:
Here's some of the code I have for the TableView controller:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
// This project has only one cell identifier, but if you are have more than one, this is the time
NSString *reuseIdentifier = cellIdentifier;
MyCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
if (!cell) {
cell = [[MyCell alloc] init];
[cell setDelegate:self];
[self.offscreenCells setObject:cell forKey:reuseIdentifier];
}
[cell.titleLabel setText:#"UILabel - I want it smaller (wrapped)"];
NSString *url = #"http://assets.bizjournals.com/seattle/news/soccer%20ball%20square*304.jpg?v=1";
[self.imageView1 loadImageForURLString:url];
[self.imageView2 loadImageForURLString:url];
[self.imageView3 loadImageForURLString:url];
[self.imageView4 loadImageForURLString:url];
// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
// Do the layout pass on the cell, which will calculate the frames for all the views based on the constraints
[cell setNeedsLayout];
[cell layoutIfNeeded];
// Get the actual height required for the cell
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
// Add an extra point to the height to account for the cell separator, which is added between the bottom
// of the cell's contentView and the bottom of the table view cell.
height += 1;
return height;
}
And here's some relevant code in my tableview cell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[self.titleLabel setNumberOfLines:1];
[self.titleLabel setTextAlignment:NSTextAlignmentCenter];
[self.titleLabel setTextColor:[UIColor blackColor]];
[self.imagesView addSubview:self.titleLabel];
[self.imagesView addSubview:self.imageView1];
[self.imagesView addSubview:self.imageView2];
[self.imagesView addSubview:self.imageView3];
[self.imagesView addSubview:self.imageView4];
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.imagesView];
self.contentView.backgroundColor = [UIColor whiteColor];
[self.titleLabel setBackgroundColor:[UIColor greenColor]];
[self.imagesView setBackgroundColor:[UIColor blueColor]];
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
}
return self;
}
- (void)updateConstraints
{
[super updateConstraints];
if (self.didSetupConstraints) {
return;
}
[UIView autoSetPriority:UILayoutPriorityRequired forConstraints:^{
[self.titleLabel autoSetContentCompressionResistancePriorityForAxis:ALAxisVertical];
}];
[self.titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
[self.titleLabel autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:kLabelHorizontalInsets];
[self.titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:kLabelHorizontalInsets];
[UIView autoSetPriority:UILayoutPriorityRequired forConstraints:^{
[self.imagesView autoSetContentCompressionResistancePriorityForAxis:ALAxisVertical];
}];
[self.imagesView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationLessThanOrEqual];
[self.imagesView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:0 relation:NSLayoutRelationEqual];
[self.imagesView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:0 relation:NSLayoutRelationEqual];
[self.imagesView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:0];
NSArray *subviews = #[self.imageView1, self.imageView2, self.imageView3, self.imageView4, self.imageView5];
[self.imageView1 autoMatchDimension:ALDimensionHeight toDimension:ALDimensionWidth ofView:self.imageView1];
[subviews autoMatchViewsDimension:ALDimensionHeight];
[subviews autoDistributeViewsAlongAxis:ALAxisHorizontal withFixedSpacing:10.0f insetSpacing:NO alignment:NSLayoutFormatAlignAllCenterY];
[subviews autoMatchViewsDimension:ALDimensionHeight];
[self.imageView1 autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
[self.imageView2 autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
[self.imageView3 autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
[self.imageView4 autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
[self.imageView5 autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:kLabelVerticalInsets relation:NSLayoutRelationEqual];
// Pin the images in the container so they appear
[self.imageView1 autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:0];
[self.imageView1 autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:0];
self.didSetupConstraints = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Make sure the contentView does a layout pass here so that its subviews have their frames set, which we
// need to use to set the preferredMaxLayoutWidth below.
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
}
So my question is this: Why isn't the UILabel wrapping my text? Am I pinning the views the right way?

Fit UIView height to its content with AutoLayout

I'm using iOS 6 AutoLayout feature with Masonry DSL to arrange views within UITableViewCell. This is the layout arrangements that I want to achieve:
The containerView is a virtual container that should dynamically adapt its size to fit its content. With my current implementation, this is what I got instead:
It seems that containerView did get vertically centered correctly, but it has zero width and height, hence not showing up properly. How can I instruct containerView to fit its size to its content? Code snippets are attached below.
Thanks!
UITableViewCell initializer
- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]) {
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont smallSystemFontSize]];
self.titleLabel.text = #"ノートタイトル";
self.coverImage = [[UIView alloc] init];
self.coverImage.backgroundColor = [UIColor carrotColor];
self.avatarImage = [[UIView alloc] init];
self.avatarImage.backgroundColor = [UIColor emerlandColor];
self.authorLabel = [[UILabel alloc] init];
self.authorLabel.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
self.authorLabel.text = #"著者の名前";
self.containerView = [[UIView alloc] init];
self.containerView.backgroundColor = [UIColor lightGrayColor];
[self.containerView addSubview:self.titleLabel];
[self.containerView addSubview:self.avatarImage];
[self.containerView addSubview:self.authorLabel];
[self.contentView addSubview:self.containerView];
[self.contentView addSubview:self.coverImage];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self updateConstraintsIfNeeded];
}
return self;
}
UITableViewCell updateConstraints
- (void)updateConstraints
{
[super updateConstraints];
[self.coverImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).with.offset(20);
make.top.equalTo(self.contentView).with.offset(5);
make.bottom.equalTo(self.contentView).with.offset(-5);
make.width.equalTo(self.coverImage.mas_height).multipliedBy(0.75);
}];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.coverImage.mas_right).with.offset(10);
make.centerY.equalTo(self.contentView);
}];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.containerView);
make.top.equalTo(self.containerView);
}];
[self.avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleLabel.mas_bottom).with.offset(5);
make.left.equalTo(self.titleLabel);
make.width.equalTo(#20);
make.height.equalTo(#20);
}];
[self.authorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.avatarImage.mas_right).with.offset(5);
make.centerY.equalTo(self.avatarImage);
}];
}
I found out the solution to my own question. Apparently, in order for containerView to resize itself dynamically, we have to make sure that each elements within are connected rigidly to each other and the edges of the superview (i.e. containerView). For example, in VFL it should be something like this: "V:|-10-[child1]-5-[child2]-5-|"
So in my case, I add a new constraint make.bottom.equalTo(self.containerView) to avatarImage and now the superview knows how to height itself!

How to set a subview's frame to be its parent's frame in a custom view

I want to set the custom view's frame as my subview's frame, which is a UILabel. but
when I use self.frame the UILabel shows empty text. I need to hardcode the parameters in CGRectMake in order to see my UILabel. How do I set the UILabel's frame to be my custom view's frame?
- (id)initWithFrame:(CGRect)frame withText:(NSString *)text
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor grayColor];
self.layer.cornerRadius = 3;
self.layer.borderWidth = 1;
self.layer.borderColor = [UIColor blackColor].CGColor;
_text = text;
}
return self;
}
- (void)layoutSubviews
{
// This works
// UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 40)];
// This doesn't work
UILabel *label = [[UILabel alloc] initWithFrame:self.frame];
label.text = #"";
if (![self.text isEqualToString:#"?"]) {
label.text = self.text;
label.textAlignment = NSTextAlignmentCenter;
}
[self addSubview:label];
}
layoutSubviews will be invoked many times, so you should not addSubview like this. Better style is to set a property of UILabel, like your text property:
#property (nonatomic, strong) UILabel * label;
then change your layoutSubviews code:
- (void)layoutSubviews
{
if(!self.label){
self.label = [[UILabel alloc] initWithFrame:self.frame]; //Use ARC
self.label.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.label];
}
self.label.frame = self.bounds;
if (![self.text isEqualToString:#"?"]) {
self.label.text = self.text;
}
}
Try with following code.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 70, 40)]; // set frame as you want
label.backgroundColor = [UIColor yellowColor]; // set color as you want
label.text = #"Hellow";
[yourParentView addSubview:label];
use this code
- (id)initWithFrame:(CGRect)frame withText:(NSString *)text
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor grayColor];
self.layer.cornerRadius = 3;
self.layer.borderWidth = 1;
self.layer.borderColor = [UIColor blackColor].CGColor;
_text = text;
[self layoutSubviews:frame];
}
return self;
}
- (void)layoutSubviews:(CGRect)myFrame
{
// This works
// UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 40)];
// This doesn't work
UILabel *label = [[UILabel alloc] initWithFrame:myFrame];
label.text = #"";
if (![self.text isEqualToString:#"?"]) {
label.text = self.text;
label.textAlignment = NSTextAlignmentCenter;
}
[self addSubview:label];
}
You do not want to create views inside the layoutSubviews method. That method can be called multiple times and you'll create each view multiple times (having them overlap each other).
Instead create the views you need in the initWithFrame method.
For the answer to your actual question, you probably need to set the frame of the new label to the bounds of the custom view. The bounds will have an origin of 0,0 and so it will work no mater where the custom view is placed in it's superview. If you use the frame, the label will be offset by however much the custom view is offset.
You can probably completely remove your layoutSubviews method as that's not the place to set the label text either. Then add this:
- (instancetype)initWithFrame:(CGRect)frame withText:(NSString *)text
{
self = [super initWithFrame:frame];
if (!self) return nil;
self.backgroundColor = [UIColor grayColor];
self.layer.cornerRadius = 3;
self.layer.borderWidth = 1;
self.layer.borderColor = [UIColor blackColor].CGColor;
_text = text;
UILabel *label = [[UILabel alloc] initWithFrame:self.bounds];
label.text = #"";
if (![self.text isEqualToString:#"?"]) {
label.text = self.text;
label.textAlignment = NSTextAlignmentCenter;
}
[self addSubview:label];
return self;
}
If you want the label to resize when the custom view resizes, you could do that inside the layoutSubviews by setting the label.frame = self.bounds;, but you'd be better off using autoresizing masks or auto layout.

Resources