Sometimes we need to define our own UITableViewCell style, which is actually adding a child view to the row. There are two main ways to add a child view: Using code and loading from a. xib file. Of course, the latter method is more intuitive.
First, basic usage
this time we're going to customize a cell so it's like a line on the QQ buddy list: The left is a picture, and the right side of the picture is a three-line label:
Of course, we're not going to get so complicated, just a little bit of fun.
1, run Xcode 4.2, create a new single View application, named Custom Cell:
2, the picture resources into the project. To this end, I looked for 14 50x50. PNG pictures, followed by the name 1, 2 、......、 14, in a folder named images. Drag this folder to the project and select Copy items into in the pop-up window ...
Upon completion of the addition, the engineering directory is as follows:
3, create a UITableViewCell subclass: Select the custom cell directory, select File-new-new File in turn, in the pop-up window, the left Choice cocoa touch, the right choice Objective-c class:
Click Next to enter the class name Customcell,subclass of select UITableViewCell:
After selecting Next and create, two files are created: CustomCell.h and CUSTOMCELL.M.
4, create customcell.xib: Select File-new-new File in turn, in the pop-up window, the left Select User Interface, the right choice empty:
Click Next, select the iphone, click Next, enter the name Customcell, and choose a good location:
Click Create, which creates the customcell.xib.
5, open customcell.xib, drag a table View cell control to the panel:
Select the newly added control, open the Identity Inspector, select Class as Customcell, and then open the size Inspector and adjust the height to 60.
6. Add controls to the newly added table View cell: Drag and drop a ImageView control to the left and set the size to 50x50. Then add three labels to the right of the ImageView, set the label size, the Top 14, and the remaining two 12:
Next, add a outlet mapping to CustomCell.h, mapping ImageView with three labels, named ImageView, Namelabel, Declabel, and loclable, respectively, for Avatar, nickname, personality signature, Place.
Select the table View Cell, open the attribute Inspector, and set the identifier to Customcellidentifier:
In order to fully use these tags, but also to create some of their own data, exist in the plist file, will do behind.
7, open CustomCell.h, add properties:
Copy Code code as follows:
@property (copy, nonatomic) UIImage *image;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *dec;
@property (copy, nonatomic) NSString *loc;
8, open CUSTOMCELL.M, add code to it:
8.1 Add code below @implementation:
Copy Code code as follows:
@synthesize image;
@synthesize name;
@synthesize Dec;
@synthesize Loc;
8.2 Add code before @end:
Copy Code code as follows:
-(void) SetImage: (UIImage *) img {
if (![ IMG Isequal:image]) {
Image = [img copy];
Self.imageView.image = image;
}
}
-(void) SetName: (NSString *) n {
if (![ N Isequaltostring:name]) {
name = [n copy];
Self.nameLabel.text = name;
}
}
-(void) Setdec: (NSString *) d {
if (![ D Isequaltostring:dec]) {
DEC = [d copy];
Self.decLabel.text = Dec;
}
}
-(void) Setloc: (NSString *) L {
if (![ L Isequaltostring:loc]) {
LOC = [l copy];
Self.locLabel.text = loc;
}
}
This is equivalent to rewriting each set function so that when an assignment operation is performed, the function we write is executed.
Well, now that the cell you've defined is ready to use.
But before we do that, we'll create a new plist to store the data we want to display. The method of establishing the Plist file is mentioned in the previous article. We built a friendsinfo.plist. Add the following data:
Note Each node type selection.
9, open viewcontroller.xib, drag a table view to view, and the delegate and DataSource point to file ' Owner, as described in the previous article.
10, open ViewController.h, add code to it:
Copy Code code as follows:
#import <UIKit/UIKit.h>
@interface Viewcontroller:uiviewcontroller<uitableviewdelegate, uitableviewdatasource>
@property (Strong, nonatomic) Nsarray *datalist;
@property (Strong, nonatomic) Nsarray *imagelist;
@end
11, open VIEWCONTROLLER.M, add code:
11.1 Add in Header:
Copy Code code as follows:
11.2 Add code after @implementation:
Copy Code code as follows:
@synthesize dataList;
@synthesize imageList;
11.3 Adding code to the Viewdidload method:
Copy Code code as follows:
-(void) viewdidload
{
[Super Viewdidload];
Do no additional setup after loading the view, typically from a nib.
Load data and pictures for plist files
NSBundle *bundle = [NSBundle mainbundle];
Nsurl *plisturl = [Bundle urlforresource:@ "Friendsinfo" withextension:@ "plist"];
Nsdictionary *dictionary = [Nsdictionary Dictionarywithcontentsofurl:plisturl];
Nsmutablearray *tmpdataarray = [[Nsmutablearray alloc] init];
Nsmutablearray *tmpimagearray = [[Nsmutablearray alloc] init];
for (int i=0; i<[dictionary count]; i++) {
NSString *key = [[NSString alloc] initwithformat:@ "%i", i+1];
Nsdictionary *tmpdic = [dictionary Objectforkey:key];
[Tmpdataarray Addobject:tmpdic];
NSString *imageurl = [[NSString alloc] initwithformat:@ "%i.png", i+1];
UIImage *image = [UIImage imagenamed:imageurl];
[Tmpimagearray Addobject:image];
}
Self.datalist = [Tmpdataarray copy];
Self.imagelist = [Tmpimagearray copy];
}
11.4 Adding code to the Viewdidunload method:
Copy Code code as follows:
Self.datalist = nil;
Self.imagelist = nil;
11.5 Add code before @end:
Copy Code code as follows:
#pragma mark-
#pragma mark Table Data Source Methods
-(Nsinteger) TableView: (UITableView *) TableView numberofrowsinsection: (nsinteger) Section {
return [self.datalist Count];
}
-(UITableViewCell *) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) IndexPath {
static NSString *customcellidentifier = @ "Customcellidentifier";
static BOOL nibsregistered = NO;
if (!nibsregistered) {
uinib *nib = [uinib nibwithnibname:@ "Customcell" bundle:nil];
[TableView registernib:nib Forcellreuseidentifier:customcellidentifier];
nibsregistered = YES;
}
Customcell *cell = [TableView dequeuereusablecellwithidentifier:customcellidentifier];
Nsuinteger row = [Indexpath row];
Nsdictionary *rowdata = [Self.datalist objectatindex:row];
Cell.name = [RowData objectforkey:@ "name"];
Cell.dec = [RowData objectforkey:@ "Dec"];
Cell.loc = [RowData objectforkey:@ "Loc"];
Cell.image = [ImageList objectatindex:row];
return cell;
}
#pragma mark Table Delegate Methods
-(CGFloat) TableView: (UITableView *) TableView Heightforrowatindexpath: (Nsindexpath *) Indexpath {
return 60.0;
}
-(Nsindexpath *) TableView: (UITableView *) TableView
Willselectrowatindexpath: (Nsindexpath *) Indexpath {
return nil;
}
12. Operation:
Second, how to reuse UITableViewCell
The purpose of reuse is to reduce memory consumption, if there are 1000 cell, if not reused, then each slide must be again
Alloc a lot of cell, consumes memory, at the same time the screen will appear discontinuous phenomenon, shake eyes.
Reusing a cell is simple, when you create a cell, you use the
Alloc Initwithtableviewcellstyle:reuseidentifer This interface to create a cell instance rather than using Alloc initwithframe
Using the former means that the cell can be reused, identifer using a fixed nsstring can
The code is as follows:
Copy Code code as follows:
-(uitableviewcell*) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) IndexPath
{
static NSString *cellidentifier = @ "Cell";
UITableViewCell *cell = [TableView dequeuereusablecellwithidentifier:cellidentifier];//first pops a cell from a reusable queue
if (cell = = nil) {//Description reusable queue inside and cell, you need to re-create the cell instance, using the following method
cell = [[UITableViewCell alloc] Initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier];
}else{//now indicates a reusable cell, which can be returned directly
NSLog (@ "cell reuse");
}
return cell;
}
How to adjust the height of the cell dynamically?
This problem is still more headaches, the following function is sure to use
Copy Code code as follows:
-(CGFloat) TableView: (UITableView *) TableView Heightforrowatindexpath: (Nsindexpath *) Indexpath
After practice, it is found that the frame can be set when creating a cell or reusing a cell
such as Cell.frame=cgrectmake (0,0,320,450);
This code works, and in the following function
Use:
Copy Code code as follows:
-(CGFloat) TableView: (UITableView *) TableView Heightforrowatindexpath: (Nsindexpath *) Indexpath
{
NSLog (@ "is currently%ld row", (long) indexpath.row);
UITableViewCell *mycell=[self Tableview:tableview cellforrowatindexpath:indexpath];//Gets the cell instance in the current IndexPath
if (MyCell = = nil) {
return 0;
}else{
NSLog (@ "%f", myCell.frame.size.height);
return myCell.frame.size.height;
}
return 0;
}
The cell instance above obtaining the current Indexpath will reapply for an instance (meaning a cell actually creates two instances)
The purpose of this is to get the frame of the cell, and if you do not do so, you can save the cell frame in a private
Variable, access to this private variable in Heightforrowatindexpath
The above method can dynamically change the height of UITableViewCell
Iv. for a uilabel, calculate the CGRect according to its content
First, you set the font for uilable, such as
Tmlabel.font=[uifont systemfontofsize:14.0f];
Then use Boundingrectofsize to calculate the size of the rectangle corresponding to this size, the code is as follows:
Copy Code code as follows:
Nsdictionary *attrdic=@{nsfontattributename:[uifont systemfontofsize:12.0f]};
Cgsize Labelsize=[text Boundingrectwithsize:cgsizemake (320, 990)
options:nsstringdrawinguseslinefragmentorigin| Nsstringdrawingusesfontleading
Attributes:attrdic context:nil].size;
CGRect labelrect=cgrectmake (0, 0, labelsize.width, labelsize.height);
Now that the rect of uilable can be computed, if a UITableViewCell is customized and its internal uilabel height is variable,
can also be achieved.
V. Uilabel with variable height inside the UITableViewCell
If there are other controls, such as UIButton and so on, it is the same.
These controls, when instantiated, set the frame to Cgrectzero, and then calculate their respective heights and dimensions respectively.
Add these subspaces to the cell using the Cell.contentview Addsubview method. When the cell frame is recalculated
You also need to add the frame of these controls. Code on:
Copy Code code as follows:
-(uitableviewcell*) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) IndexPath
{
static NSString *cellidentifier = @ "Cell";
UITableViewCell *cell = [TableView dequeuereusablecellwithidentifier:cellidentifier];
if (cell = = nil) {
cell = [[UITableViewCell alloc] Initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier];
Uilabel *label = [[Uilabel alloc] Initwithframe:cgrectzero];
Label.tag = 1;
Label.linebreakmode = nslinebreakbycharwrapping;
Label.highlightedtextcolor = [Uicolor Whitecolor];
Label.numberoflines = 0;
Label.opaque = NO; Select opaque to indicate that nothing behind the view should be drawn
Label.font=[uifont systemfontofsize:12.0f];
Label.backgroundcolor = [Uicolor Graycolor];
[Cell.contentview Addsubview:label];
UIButton *tmpbutton=[[uibutton Alloc]initwithframe:cgrectzero];
tmpbutton.tag=2;
Tmpbutton.backgroundcolor=[uicolor Cyancolor];
[Cell.contentview Addsubview:tmpbutton];
Tmpbutton.opaque=no;
[Tmpbutton settitle:@ "Nihao" forstate:uicontrolstatenormal];
[Tmpbutton settitlecolor:[uicolor Whitecolor]forstate:uicontrolstatehighlighted];
[Tmpbutton addtarget:self Action: @selector (Tmpbuttonhandler:) forcontrolevents:uicontroleventtouchupinside];
}else{
NSLog (@ "cell reuse");
}
Uilabel *tmplabel= (Uilabel *) [cell viewwithtag:1];
NSString *text=[tmparray ObjectAtIndex:indexPath.row];
Tmplabel.text=text;
UIButton *tmpbutton= (UIButton *) [cell viewwithtag:2];
Nsdictionary *attrdic=@{nsfontattributename:[uifont systemfontofsize:12.0f]};
Cgsize Labelsize=[text Boundingrectwithsize:cgsizemake (320, 990)
options:nsstringdrawinguseslinefragmentorigin| Nsstringdrawingusesfontleading
Attributes:attrdic context:nil].size;
CGRect labelrect=cgrectmake (0, 0, labelsize.width, labelsize.height);//Calculate Uilabel rect
[Tmplabel Setframe:labelrect];
[Tmpbutton setframe:cgrectmake (0, labelsize.height+1, 100, 50)];//compute UIButton for rect child controls
[Cell setframe:cgrectmake (0, 0, labelsize.width, labelsize.height+50+1)];//cell frame is the sum of the above two child controls
return cell;
}
Why set the frame when it is no longer created, but behind the IF and else logic?
When you reuse a cell, the cell that is removed from the Reuse cell queue, and its contents (Uilabel) is the previous cell content, needs to repopulate the Uilabel and recalculate
The frame of the entire cell and sets its frame. When you create a cell, you also need to set the frame, so the two logics are repeated and placed directly outside of the if else logic.