Two customize cells in UITableView - ios

I would like to know if it's possible to have 2 customize cells in one UITableView ?
Because I would like to have two different type of cells in one view : the first row will be big (with white background on screenshot), and after simple row (with red background on screenshot).
Tell me if that's possible or not, and how to make that :)
I let you see what I want to make :
http://www.noelshack.com/2015-13-1427415385-sans-titre.png
Or maybe put a UIView for big label, and after table cell ?

There are 2 approaches, assuming that the big screenshot is only on the first row. You could set the table view's property
tableView.tableHeaderView = myHugeImage;
Otherwise, if you design 2 rows using nibs and custom classes, you'll need to call the following in viewDidLoad. Do note that custom classes must be subclasses of UITableViewCell
[tableView registerNib:[UINib nibWithNibName:#"bigrow" bundle:nil] forCellReuseIdentifier:#"big"]
[tableView registerNib:[UINib nibWithNibName:#"normal row" bundle:nil] forCellReuseIdentifier:#"normal"]
If you used classes and no nibs, then you would use registerClass:forCellReuseIdentifier
If you used classes and designed the cell directly inside the prototype cell, then neither of those calls are necessary.
Lastly, inside tableView:cellForRowAtIndexPath:
if (indexPath.row == 0) {
BigRowCell *c = [tableView dequeueReusableCellWithIdentifier:#"big" forIndexPath:indexPath];
return c;
}
SmallRowCell *c = [tableView dequeueReusableCellWithIdentifier:#"normal" forIndexPath:indexPath];
return c;

Related

How to reuse UITableViewCell for different type of cells

I have a UITableView that has different types of cells in it.The common approach is to have different UITableViewCells and reuse them depending on the data object.
Now, I have 9 different types of data objects. But my view is similar to the Facebook feed view with like button, comments button, user image and user name. Only the centre view changes based on the data object.
My question is, should I use 9 different type of cells with a common class for these elements or should I use one cell and add the centre view as and when the cell is created?
Currently my approach is to use one cell and add the centre view. Will the UITableViewCell be re-used if we follow that approach?
The table view cells will always be reused if you initialize the cell with reuseIdentifier: and use the dequeueReusableCellWithIdentifier: method on the table view.
As far whether to use a single UITableViewCell subclass or several, it depends on how much is different between each of your 9 content types. If they all contain the same UI elements, using 1 subclass makes sense. Otherwise, you can create multiple subclasses and still reuse the cells with dequeueReusableCellWithIdentifier: as long as you pass in a different unique identifier for each subclass. Each subclass would be independently reused.
Here's what your cellForRowAtIndexPath: could look like if you're using multiple cell classes:
NSString *primaryCellID = #"PrimaryCellID";
NSString *secondaryCellID = #"SecondaryCellID";
if (someCondition) {
CustomTableViewCell1 *cell = [tableView dequeueReusableCellWithIdentifier:primaryCellID];
if (!cell) {
cell = [[CustomTableViewCell1 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:primaryCellID];
}
return cell;
}
else {
CustomTableViewCell2 *cell = [tableView dequeueReusableCellWithIdentifier:secondaryCellID];
if (!cell) {
cell = [[CustomTableViewCell2 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:secondaryCellID];
}
return cell;
}

Multiple UITableViews as cells to one UICollectionview, more efficient Cell Reuse/Creation

I've got multiple (n) tableviews I need to display horizontally. I am using a UICollectionView where each collection view cell has a UITableView. Each tableview takes up most of the screen, there are three tableviews (three cells) displayed at a time, with only a few pixels of the left and right tableviews showing when there is no scrolling going on. All the table views are objects of the same class, and all use only one type of cell.
My problem is that every time I scroll to display the next tableview, all of the cells in the tableview have to be allocated and init'ed. This is very expensive, and there is an obvious split second freeze if the new tableview has a full set of cells to display. I had the idea of making a UITableView in my parent class (the one holding the UICollectionView) calling it a prototypeTableView and when I create the tableview cell I set that prototypeTableView as a property of that cell (the tableview).
Here is the code in my Parent class that holds the UICollectionView. Where I set the prototypeTableView to the
CollViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CollViewReuse forIndexPath:indexPath];
cell.theTableView.prototypeTableView = self.prototypeTableView;
Here's the code in my UITableView child class
MyTableViewCell *cell = [self.prototypeTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
My problem is that I get a nil cell back every time I dequeue a cell. If there is a better way to do this please let me know. I just wanted to test this and I can't completely call this a bad way to do it until I can get the table view to actually dequeue my cells!
Thanks!!

IOS7 Custom TableViewCell will not appear

I am trying to create a project with a custom UITableViewCell. The custom cells never load, they're just blank. At this point in the project what I'm trying to do is placing a UITableViewCell in a .xib, designing it the way I want and specifying its reuse identifier along with tag IDs for the components so that I can use them in code later on.
I've googled a ton and found several tutorials that look like what I want to do, along with many SO questions that have answers that seem applicable. At this point it's probably just my head spinning with too many different angles and solutions.
This is my current attempt at trying to register the custom cell with my UITableView, yet when running this on a device the rows in the table view are entirely blank.
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
UILabel* l1 = (UILabel*)[cell viewWithTag:1];
UILabel* l2 = (UILabel*)[cell viewWithTag:2];
UILabel* l3 = (UILabel*)[cell viewWithTag:3];
l1.text = #"Foobar";
l2.text = #"Foobar";
l3.text = #"Foobar";
I'm pretty certain that I've hooked up all the properties and such correctly, but at this stage I need a fresh pair of eyes to point out the facepalm for me.
The interesting files are FilmerView.m/h/xib and the cell is in FilmerViewCell.xib. When running the app this TableView is in the second tab of the tab bar controller.
Project:
http://speedy.sh/WhhpP/test12.zip
I can't provide a full answer atm but look up the tableview method. registerNib:forCellReuseIdentifier:
Also, stop using that dequeue method. Use the one that includes the indexPath.
Then you don't have to check if the cell is nil afterwards.
EDIT
In viewDidLoad (or somewhere like that)...
UINib *cellNib = [UINib nibWithNibName:#"MyCustomCellXibFileName" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:cellNib forCellReuseIdentifier:#"CellIdentifier"];
Now in the table view datasource method...
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// no need to check cell == nil.
// this method is guaranteed to return a non nil cell.
// if it doesn't then the program will crash telling you that you need to...
// register a class or nib (but we just did this in viewDidLoad) :D
// configure your cell here...
[self configureMyCell:(MyCustomCell *)cell atIndexPath:indexPath];
return cell;
}
- (void)configureMyCell:(MyCustomCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.nameLabel.text = #"Hello, world";
}
Hope this helps.
Make sure that you have set datasource and delegate properties of your tableView.
Make sure that you have implemented (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method and it returns a positive value (>0).
Evaluate the following:
Is the ReuseIdentifier set in the XIB. See Properties Tab in Interface Builder on the right when selecting the cell.
Are the AutoresizingMasks set properly for the labels to be visible?
WrapModes: Which did you select? When having wrapmode WrapWord, is the font size too large for the text to be moved in the next line becoming invisible?
Set the background color of the UITableViewCellss content view to something else than white or transparent, as well as the background colors of the labels to see if the cell is even there.
Manually call numberOfRowsInSection on your table, pass the proper NSIndexPath identifying the target section and see if its greater 0 to confirm that the TableView even attempts to load the data, thus, the cells. ( Alternatively set a breakpoint in the method or do a NSLog. )
Do a NSLog in cellForRowAtIndexPath to confirm that the cell returned is not nil and the method is even called!

How do I have a UITableView with two different cell types and set each of the`cell layouts up programmatically, instead of via a Storyboard?

Previously I had this set up with a storyboard, having dragged the UILabels, positioned them and sized them whatnot on the UITableViewCell I dragged them onto, and then do a different version of that for the other UITableViewCell.
For example, like follows (but in the picture they've yet to be customized with the labels):
Then in the datasource, I'd simply check the Identifier, and depending on what the Identifier was, customize the cell accordingly.
However, I've needed more customization than I can get from the storyboard, as each cell is going to have two UIViews (a top one and a bottom one to allow sliding of the top one) so I can't really do this with storyboarding, as I add the labels and everything to the UIView programmatically.
But my question is: When I do it programmatically, how can I tell which cell is which so I can customize the layout of the UILabels accordingly? With a storyboard I can obviously just drag a UILabel onto each one, but when doing it programmatically and setting up the UIView, I don't know how to say, "Hey, if the identifier is this, add the UILabels like so" because the UIViews aren't aware of any Identifiers.
Basically the structure looks like this:
UITableView -> UITableViewCell -> CellFront(UIView) & CellBack(UIView)
And the look of the cell comes from the labels added to the CellFront UIView. But there's two looks to the cells and I don't know how to do it without a storyboard.
Although UIViews are not aware of identifiers, they have a property called tag which can be used for any purpose that you would like. You can set the tag to, say, 1 on cells of one kind, and to 2 on cells of the other kind, and then use the tag to distinguish the cells in code. Moreover, once your views are tagged, you can call viewWithTag: on the containing view, and get back the view with the tag that you want.
If you are creating the cells solely in code, then you register your UITableViewCell subclass in the viewDidLoad method of your table view controller. That method sets the identifier. Then, you use that identifier in cellForRowAtIndexPath: just like you would for a xib or storyboard created cell.
[self.tableView registerClass:[MyCellSubclass class] forCellReuseIdentifier:#"MyIdentifier"];
Here is one approach:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Adjust the condition to match your needs
if (indexPath.row == 0) {
static NSString *Identifier1 = #"CellType1";
// cell type 1
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier1];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier1];
// add subviews here
}
// set cell properties
return cell;
} else {
static NSString *Identifier1 = #"CellType2";
// cell type 2
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier2];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier2];
// add subviews here
}
// set cell properties
return cell;
}
}

UITableView cells not drawing until the cell is at the top of the screen

I am building a table where each cell of the UITableView is a UIViewController. I have three different UIViewControllers I need to show in three rows of the table. I set the row of each cell to match the size of the UIViewController so each row is a different height.
When the app first starts, only the UIViewController in the first cell shows up. The contents of the next row doesn't show up until I scroll the table so that the top of that row is at the top of the screen. Likewise if I scroll down slightly so that a row is slightly off the bottom of the screen, when I scroll back up a little, the row contents are gone.
Here's the code I'm using. Note: The controllers to are created in the viewdidload method
What am I missing? Thanks
- (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] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch(indexPath.section)
{
case 0:
{
[cell.contentView addSubview:patientInformationController.view];
break;
}
case 1:
{
[cell.contentView addSubview:labsController.view];
break;
}
case 2:
{
[cell.contentView addSubview:planController.view];
break;
}
default:
break;
}
}
return cell;
}
UITableViewController is a huge, high-level construct for efficiently managing entire screens of data and UI objects. UITableViewCell is a tiny, efficient, highly-optimized view class designed to be drawn and updated as fast as possible.
Do not, ever ever ever, add a UIViewController's view to the contentView of a UITableViewCell. A few labels, an image, maybe a small control such as a UISwitch or UITextView.
If you haven't already, start reading here.
If you want to associate your view controllers (patientInformationController, labsController) with a particular row of the table view, the proper method is to just set the cell label for that row to a human-readable string, such as #"Patient Information", or #"Labs", and then, when the row is selected, use a UINavigationController to push the proper view controller.
UINavigationController manages a stack of UIViewControllers. A UIViewController manages a single coherent interface, usually comprised of a bunch of cooperating views. UITableViewController is a subclass of UIViewController which manages a single UITableView. UITableView is a class which specializes in the lightning-fast rendering and presentation of tabular data, organized into sections and rows according to a delegate and data source that you provide. One of the capabilities of UITableView is to inform its delegate in the event of the user selecting a row of the UITableView, allowing the delegate to present, via a UINavigationController, a new UIViewController for the presentation to the user of yet more detail and functionality.
Hope this helps. Start reading.

Resources