I am trying to create a label in each of my customCells. In cellForRowIndexPath, I have:
EDIT:
static NSString *checkInTableIdendifier = #"ChatCell";
cell = (ChatTableViewCell *)[tableView dequeueReusableCellWithIdentifier:checkInTableIdendifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSAttributedString *title;
title = [[NSAttributedString alloc] initWithString:[self.savedMsgs objectAtIndex:indexPath.row] attributes:#{ NSFontAttributeName : [UIFont fontWithName:#"Noteworthy-Bold" size:12], NSUnderlineStyleAttributeName : #1 , NSStrokeColorAttributeName : [UIColor blackColor]}]; //1
UILabel *label;
label = [[UILabel alloc] initWithFrame:CGRectMake( (self.view.bounds.size.width - title.size.width) / 2.0f, 40.0f, title.size.width, title.size.height)]; //2
label.attributedText = title; //3
[cell addSubview:label]; //4
The label will all end up in the same point overlapping each other because of line 2. How can I represent the origin of the label generated according to each respective cell?
The method you are using to generate cells, 'dequeueReusableCellWithIdentifier' can return a cell that has already been used before. When you add your labels etc after getting the cell, you are adding labels on top of labels that are already there.
The easiest way to handle cell reuse is to create a UITableViewCell subclass and an associated xib. After this ViewController is created and the tableView is accessible (viewDidLoad, usually) register the nib for the cell to the tableView. Then when you dequeue the cell, you need only to set the text values on the labels that are already there.
An aside, UITableView had a newer better method for dequeuing cells that takes an index path and always returns a cell so you don't need to nil check it. I would switch to that if you don't need to support iOS 6.
You should use the cell's bounds, not self.view's to position the label. Be careful as the frame might change after the cell has been created, so it's recommended to use auto layout to ensure the label is always positioned when you want it to be in respect to the cell.
Also, remember that the cell get reused in which case you might end up adding the label multiple times.
To mitigate both issues, subclass the cell and design it in the accompanying xib.
Related
I am struggling to figure out how to get complete control over my tableview cells. I want them to look something like this:
Right now I need to know how to properly manage my cells. Should I make a table view cells subclass? Should I be doing this all within the storyboard of the tableview? That's what I'm doing now. Also, how do I implement dynamic cell heights based on the amount of lines of text?
Thanks
You should subclass the UITableViewCell class and create your own custom cell using XIB. This will give you a lot of leg room for dynamism.
Refer to this tutorial for how to do so:
http://www.appcoda.com/customize-table-view-cells-for-uitableview/
U can create a custom view and use the followingin the cellForRowAtIndex
static NSString * cellIdentifier=#"MyTableView";
UITableViewCell * cell;
if(cell== nil)
{
cell = [myTableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
contentCell.tag =100;
contentCell=[[ContentOfCell alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
[cell.contentView addSubview:contentCell];
}
else{
// Reusable part. Reuse the UI controls here from existing cell
contentCell = (ContentOfCell *)[cell.contentView viewWithTag:100];
}
//Assign all the data here
contentCell.nameField.text=[arr objectAtIndex:indexPath.section];
//same way for other fields
}
Where contentCell is a custom view
I will try to answer your question in three parts :
For Dynamic cell height which is based on text content : you have a table view delegate called heightForRowAtIndexPath, you should calculate the height of the text based on its font and font size characteristics, and of course by providing the available width, for this you can use method "sizeWithFont" of NSString.
For more control on the cell appearance : you should make a table view cell subclass and use it in the cellForRowAtIndexPath.
Should you be doing this using storyboard : It is not necessary to do it using storyboard.
I made a custom table view cell - i have a header, implementation, and nib. In the nib I set the style to custom, dragged a label on it and made an outlet in the nibs file owner.
From my UITableView Controller I have this code:
static NSString *CellIdentifier = #"adbActivityCell";
adbActivityCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
//cell =[[adbActivityCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.price.text = [NSString stringWithFormat:#"cell #%d", indexPath.item + 1];
return cell;
If I run this as is XCode tells me that the UITableView Controller is not key value compliant for the label property (the label is named "price"). If I comment out the two lines above and uncomment that one line my application runs, but the label doesn't show up at all, even if I set default text for it.
I've spent quite a lot of time researching tutorials and questions on here with no luck.
Its all about view hierarchy.
You have to add your label outlet to the custom UITableViewCell, because it is the superView of your label in view heirarchy.
That means label is contained in custom cell thats why you have add outlet to custom cell.
self.view->tableView->CustomCellView->UILabel
In your customCell.h file set the IBOutlet of the label. Your problem will be solved.
I'm new in iOS programming that's why I'm looking for the most efficient solution to my problem.
What I want to achieve is to display in UITableViewCell with a name (some text) and under each name some filled little rectangles with a number inside, similar to badges.
My first idea is to create a UIView that will represent the badge and in a custom UITableViewCell I will add these rectangles as subviews.
The second idea is to create only one UIView that will draw all the little rectangles.
My question is, which is the better performing solution knowing that:
the number of cells will be max. 20 and the total number of rectangles no more than 50
The number of rectangles displayed in a cell is different
I want to reuse the cells, so I have to update/redraw the cell content for each row
I want to avoid the cell selection view problem that "hides" the subviews
Of course any other solution is appreciated.
Thanks in advance,
hxx
What i would suggest is to sub class the UITableViewCell and make the customization u need in it.The customized view can have a label and rectangles below it.
The rectangles can be small custom buttons with background images (if you have any or give it a background color) and title as your number.You would have to ,however calculate their width based on the width of your table to accomodate the maximum number of rectangles.
You can disable the selection of the table in the xib or you can do it programmatically like so cell.selectionStyle = UITableViewCellSelectionStyleNone; and do not implement didSelectRowAtIndexPath
I have followed the approach of subclassing the cell for my tables to customize their look and feel and it works good.I hope this helps.
A Good tutorial to begin with subclassing can be found here
http://howtomakeiphoneapps.com/how-to-design-a-custom-uitableviewcell-from-scratch/1292/
Why you are not creating cell in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath Here you can defines your custom type cell which will also reuse and whenever you want you can add the different thing to cell like this.
static NSString *CellIdentifier = #"Cell";
UILabel *RequestSentTo;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
cell.selectionStyle=UITableViewCellSelectionStyleNone;
RequestSentTo = [[UILabel alloc] initWithFrame:CGRectMake(11, 2, 286, 40)];
RequestSentTo.backgroundColor = [UIColor clearColor];
RequestSentTo.tag = 200;
RequestSentTo.numberOfLines = 3;
RequestSentTo.font=[UIFont boldSystemFontOfSize:15.0];
RequestSentTo.textColor = [UIColor blackColor];
RequestSentTo.lineBreakMode=UILineBreakModeWordWrap;
[cell.contentView addSubview:RequestSentTo];
} else {
RequestSentTo=(UILabel*)[cell.contentView viewWithTag:200];
}
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"Shift Request for "];
[string appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"%# by ",dateStr] attributes:nil]];
[string appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"Dr. %#",notificationsObj.doctorName] attributes:purpleTextAttributes]];//purpl
RequestSentTo.attributedText=string;
RequestSentTo.lineBreakMode=UILineBreakModeWordWrap;
RequestSentTo.numberOfLines = 3;
Whenever you want you can add the things you want with reusing cell. Hope this helps
2 methods come into my mind.
You can put the components as subview inside UITableViewCell(Through XIB or programatically subclassing UITableViewCell) and use it in UITableView.
You can subclass UITableViewCell, and override the -(void)drawRect method and draw all the components that you wish to be displayed on cell.
See if can help.
You can create a new class extends to UITableViewCell, which means to rewrite UITableViewCell as your own cell named as MyTestCell.
And in this Cell you call create your properties, like labels and views, and add those to your new cell.
like add this to MyTestCell.h
#property (nonatomic, retain) UILable *myLable1;
#property (nonatomic, retain) UIView *mySubview1;
MyTestCell.m
_myLable1 = .....
_mySubview = .....
[self addSubview: _myLbale1];
[self addSubview: _mySubview1];
And when use, u can work like this
static NSString *CellIdentifier = #"MyCell";
MyTableViewCell *cell = [tableview dequeReuseID:CellIdentifier];
if (cell == nil) {
cell = [MyTableViewCell alloc] init.........
}
//And you can sign your property here in your cell
cell.myLable1 = ....
cell.myView1 = .....
return cell;
}
If your strings add to the lable is different,make the lable.height is different. you can use code like this
CGSize labelSize = [str sizeWithFont:[UIFont boldSystemFontOfSize:17.0f]
constrainedToSize:CGSizeMake(280, 100)
lineBreakMode:UILineBreakModeCharacterWrap]; //check your lableSize
UILabel *patternLabel = [[UILabel alloc] initWithFrame:CGRectMake(35, 157, labelSize.width, labelSize.height)];
patternLabel.text = str;
patternLabel.backgroundColor = [UIColor clearColor];
patternLabel.font = [UIFont boldSystemFontOfSize:17.0f];
patternLabel.numberOfLines = 0;// must have
patternLabel.lineBreakMode = UILineBreakModeCharacterWrap;// must have
add this to your cell, and make it dynamically resize your lable as well as your cell! And also you have to dynamically set high for your tableView Row height.(Do know what is dynamically resize?)
See this:
rewrite the method setMyLable1 in MyTableViewCell.m
-(void)setMyLable1:(UILable*)aLable
{
//in here when never your sign your alabel to your cell (like this : cell.myLable1) this method will be call and u can get the size of your string and set this label's height
//get string size StringSzie
[_myLable1 setFrame:CGRectMake(10,10,stringSize.width,stringSize.height)];
//And resize your cell as well
[self setFrame:CGRectMake(0,0,_myLable1.frame.size.width+20,_myLable1.frame.size.height+20)];
//done!!!
}
OK you get a automactically reszie cell for yourself and you have to dynamically reset height for your row in tableView too!!!!!
What do you need is called custom cell
Here is good tutorial for it
customize table view cells for uitableview
I've done my research and followed the numerous guides for this process, including:
Adding unknown number of rows to 'Static Cells' UITableView
https://devforums.apple.com/message/502990#502990
But a recurring theme in the follow-up questions is always "The TableViewCells show up, but they are empty." I assume people solve the problem, but no solutions are posted.
Thus, the stage I am at consists of: the static cells showing up and being correctly filled with data, and the dynamic cells correctly show up in quantity, but not with their elements (they are empty).
I believe I have everything hooked up correctly. I have:
In my UITableViewController subclass, included and overridden all required methods as marked as "Answer" in the two links above.
Subclassed UITableViewCell, and included two UILabel properties in the subclass.
Set the class for the cell in Storyboard to my subclass, and given an appropriate Identifier, which is correctly used in the Controller subclass.
Placed two UILabels on the cell in storyboard.
Hooked up the two labels to the properties in the Cell subclass.
I instantiate and assign values to the properties just like in the answers above.
static NSString *CellIdentifier = #"DynamicCell";
OwnersInfoEventsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[OwnersInfoEventsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.eventName.text = #"Name"; //this doesn't show up
cell.eventNeed.text = #"Need"; //this doesn't show up
cell.backgroundColor = [UIColor redColor]; //this works, the cell shows up red
return cell;
What am I missing?
That happened to me and the problem was that when you create your own cell (in case you don't find a reusable one) its two labels are nil. So you also has to create two labels and set them as the labels of your cell and it would hopefully work.
First you need to check that you have defined OwnersInfoEventsCell properly. Check that Label that you defined in Cell Class is properly defined. Check frame of that label.
_ eventName = [[UILabel alloc]initWithFrame:CGRectMake(25, 2, 40 , 40)];
_ eventName.backgroundColor = [UIColor clearColor];
[_ eventName setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
eventName.font = [UIFont fontWithName:#"King" size:12];
[self.contentView addSubview:_ eventName ];
check that you have added label in cell's content view. This may be issue. let me show your code of OwnersInfoEventsCell then i can suggest you more briefly.
Hope this may help you.
I had always been told that if I have a UILabel with dynamic text content in it that I should use SizeToFit as that would adjust the UILabel properly. I used sizeToFit but it was messing up my text labels that were on a UITableViewCell after I did a scroll. However on initial screen load, they would appear fine.
After messing with it for a couple of hours I read somewhere that someone else had the same issue and that instead of SizeToFit they used the following two lines:
cell.message.lineBreakMode = UILineBreakModeWordWrap;
cell.message.autoresizingMask = UIViewAutoresizingFlexibleHeight;
and it would work. Well I did and my UILabels are perfect. However I am still curious in understanding why so?
so now my code looks like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessagesCustomViewCell";
MessagesCustomViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MessagesCustomViewCell_iPhone" owner:self options:nil];
cell = [nib objectAtIndex:0]; //you can also loop thru or manually remember positions
}
NSArray * discussion = [self.messages objectAtIndex:indexPath.row];
cell.author.text = [discussion valueForKeyPath:#"author.name"];
cell.message.text = [discussion valueForKey:#"text"]; //DYNAMIC VARIABLE SIZED TEXT
cell.message.lineBreakMode = UILineBreakModeWordWrap;
cell.message.autoresizingMask = UIViewAutoresizingFlexibleHeight;
return cell;
}
sizeToFit
behavior:care about its content over superview's size
send sizeToFit to a UILabel without [yourLabel setNumberOfLines:0] will make the Label as wide as possible to fit it's text. While with [yourLabel setNumberOfLines:0] your label will break it's text to mutiple lines according it's width, but this will make it's height as large as possible to fit in it's text, it does not care about it's superview's bounds.
autoResizingMask
behavior:care about superview's size over its content
If a UIlabel's autoResizingMask is set, once it's superview's bounds is change, it will change it's frame first, then it checks "Can i put more text in my rect?" base on it's relative properties(numberOfLines, font,...).