Static UITableView with custom row heights - ios

I'm trying to create detail view controller as a list of information and I think it would be nice and clean to present this with a static UITableView. But after that it came to my mind that on some level it might be difficult, so please resolve my doubts!
Every UITableViewCell has different style (some are custom, some are basic and few are right-detailed etc.).
What is more, content size of each cell may vary as I have long names put inside labels so they use autolayout to fit.
There is no problem when I have the same cells repeating but with different tex inside UILabels. In that case I use a simple:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.prototypeCell) {
self.prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:#"ActivityCell"];
}
[self fetchedResultsController:[self fetchedResultsController] configureCell:self.prototypeCell atIndexPath:indexPath];
CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height;
}
I don't know how to deal with heightForRowAtIndexPath. I can give an identifier to each cell, call cellForRowAtIndexPath:, and make a big switch or if statement, but is it right? The same problem occurs while I think of cellForRowAtIndexPath: and populating those UITableViewCells. With those testing statements this code won't be pretty and readable.
Any ideas on that case?

In the delegate function of the table view named heightForRowAtIndexPath try to calculate the height for each row and then return it.
//return height for row
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView==tblLanguage)
{
//Here calculate the dynamic height according to songs count for specific language
return (([[arrSongListForSpecificLanguage objectAtIndex:indexPath.row] count]*40)+40);
}
return 40.0;
}

Related

Xcode remove cell with animation programmatically

Hi i have been searching around to find a way to remove a static cell with animation but i have not found a solution to the problem.
I have also tried: [tableView deleteRowsAtIndexPaths:[self.taskArray objectAtIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationFade];
but no success.
You need to hide cell before it is shown, in UITableViewDelegate's tableView:willDisplayCell:forRowAtIndexPath: method. This is the last method in your control where you can manipulate the cell display. It does not remove the space the cell takes, so another thing you can try is to set cell row's height to 0 using the tableView:heightForRowAtIndexPath: method of the same protocol.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (yourCell) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
As your tableview is static, you cannot use deleteRowsAtIndexPath. The best option would probably be to migrate your data into a dataSource method for the tableview.
If this is impossible, then this answer ("UITableView set to static cells. Is it possible to hide some of the cells programmatically?") gives that the best method is to use the third party library
StaticDataTableViewController 2.0 (https://github.com/xelvenone/StaticDataTableViewController).
Otherwise you have to use the somewhat hacky method of changing the row height to 0.

Mixing static and dynamic sections in a grouped table view

I need a grouped UITableView similar to the one for Twitter accounts in Settings app:
That is, a sort of form or menu where some of the sections have a beforehand known set of static cells, and some other sections have to be dynamic and allow inserting additional rows the same way the "Add Account" does here. I'm managing the UITableView in a .xib file. For the static cells, I have separated .xib files that I can load within the cellForRowAtIndexPath: method in the view controller.
How should I handle this kind of table? I donĀ“t find any example code.
How the cellForRowAtIndexPath: method should look like? May I need to keep strong properties for the static cells? Would it be better to design each static cell directly within the same .xib file where the table view is, and to set outlets for them? (Though this does not allow to reuse my custom cells design...)
I need some guidelines for achieving this and correctly managing cells and memory. Thanks in advance
Dynamic prototype cells can behave like static ones if you just return the cell without adding any content in cellForRowAtIndexPath, so you can have both "static like" cells and dynamic ones (where the number of rows and the content are variable) by using dynamic prototypes.
In the example below, I started with a table view controller in IB (with a grouped table view), and changed the number of dynamic prototype cells to 3. I adjusted the size of the first cell to 80, and added a UIImageView and two labels. The middle cell is a Basic style cell, and the last one is another custom cell with a single centered label. I gave them each their own identifier. This is what it looks like in IB:
Then in code, I did this:
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = #[#"One",#"Two",#"Three",#"Four",#"Five"];
[self.tableView reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 1)
return self.theData.count;
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0)
return 80;
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"TitleCell" forIndexPath:indexPath];
}else if (indexPath.section == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:#"DataCell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
}else if (indexPath.section == 2) {
cell = [tableView dequeueReusableCellWithIdentifier:#"ButtonCell" forIndexPath:indexPath];
}
return cell;
}
As you can see, for the "static like" cells, I just return the cell with the correct identifier, and I get exactly what I set up in IB. The result at runtime will look like your posted image with three sections.
Static is just a provision on top of dynamic layout. Basically static is a WYSIWYG.
If you are not resistant to experiment with values, I would recommend go dynamic. There are hundreds of examples available, such as this and this.
As you go further, you would see yourself diverging towards two options when customizing dynamic table views:
Subclass UITableViewCell (more effort , but good in the long run). Again, follow this.
Play with UITableViewCell properties inside cellForRowAtIndexPath: (less effort and quick result but may or may not be performance-friendly due to possible redrawing)
The possibilities are endless, such as here where cell background view is customized.

Calculate custom UITableViewCell height at "indexPath" from -tableView:cellForRowAtIndexPath:?

I adjust the height of a custom UITableViewCell inside the custom class, and I believe I need to use the -tableView:cellForRowAtIndexPath: method to adjust the height of the cell. I am attempting to just adjust the height of the custom cell in the custom cell class, then grab the cell at the given index path cast it, and return the height of that cell like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
CustomUITableViewCell *cell = (CustomUITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
return cell.frame.size.height;
}
But I am getting stack overflow. What is a better way around doing this?
The table view delegate will first call heightForRowAtIndexPath: and then the datasource will construct the cell in cellForRowAtIndexPath: after that based on the computed information.
Therefore your approach will not work.
You need to have some logic for computing the height. (E.g. if you are displaying text the height might be dynamic and depend on the amount of text - you could calculate that with an NSString method.)
If you are just displaying a few types of cells with fixed heights, simply define these heights as constants and return the correct height based on the same logic you have in cellForRowAtIndexPath: to decide which cell to use.
#define kBasicCellHeight 50
#define kAdvancedCellHeight 100
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (needToUseBasicCellAtThisIndexPath) {
return kBasicCellHeight;
}
return kAdvancedCellHeight;
}
If it's a storyboard cell, you can call dequeueReusableCellWithIdentifier:. Otherwise, you can just instantiate the cell directly with something like [CustomUITableViewCell alloc] initWithFrame:].
I use this approach (using a prototype cell to calculate height) myself because it allows our designer to modify storyboard cells without requiring code changes.
You may want to adjust your approach based on whether the height is static or dynamic as discussed here.

Custom "Floating" UITableViewCells

I have been searching the web for an answer to this and I am sure it has an easy answer.
I am creating an UITableView in my app and I am wanting it to have "floating" table view cells and a menu at the top. Like this:
I am sure that these are custom UITableView Cells, but I am not sure how to create them like this and have them be dynamic in size based on the content and how to include a menu at the top that disappears/shows once the user scrolls down or up.
Any insight on this would be awesome!
This can be done fairly easily with a subclassed UITableViewCell in a grouped table view. The image below shows one I quickly made by dragging in various UI elements, and creating a custom class, which has nothing but IBOutlets in the .h file.
The label with the gibberish in it is tied to the gray view below and to the top of the cell, with no specific height set, so when the cell grows, it will grow. Here is the code I used to populate the table:
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = #[#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine"];
[self.tableView reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.theData.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *s = #"asdfhfl fl flfh sflhsalfjh fajlhf lf asldf fh asljfafh sjlfh ajf fljf fasjlfhjfhjfhjsf hsjfhsjfhajsfh the end";
CGSize size = [s sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:CGSizeMake(281, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
return size.height + 130;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RDCell *cell = [tableView dequeueReusableCellWithIdentifier:#"RDCell" forIndexPath:indexPath];
cell.lbl1.text = self.theData[indexPath.section];
cell.lbl2.text = #"asdfhfl fl flfh sflhsalfjh fajlhf lf asldf fh asljfafh sjlfh ajf fljf fasjlfhjfhjfhjsf hsjfhsjfhajsfhajlfjafh";
return cell;
}
Notice that I set the number of sections to the count of the array, so you get separate sections of 1 row each. The code in the heightForRowAtIndexPath is typical of the way you would calculate the cell height (except that you would normally use the index path and get a different string for each cell).
I think thats what you are looking for..
IBScrollViewFloatingHeader

How can I customize some of a UITableView's cell heights, but leave others as defaults?

To specify cell heights of a table view we use the delegate method,
- (CGFloat) tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section
However this method asks cell height of every row, what can I do if I want some of them to be defaults?
For cell height we may return UITableView#rowHeight for those default rows inside the delegate method, but I also want some (not all) of the section headers/cell to be customized.
But I am not able to get the defaults from the table view, especially for grouped style table view, anyone has a solution?
Thanks!
EDIT: I'm sorry for not making it very clear. In fact, cell height is not the only one that I want to partially customize, but also something else like section header (there may be more, like delete button style, etc.).
Is there solution without mimicking default behavior?
if you don't want default behavior in all cases, you'll still have to mimic default behavior in the non-specialized cases.
for headers, you will still have to implement
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
and therein, you will have to answer the default height for those headers you do not wish to change, and the specialized header height for those you do want to change.
similarly, in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*);
you will still have to mimic default behavior for those cells you do not wish to change.
you could accomplish all of this with storyboard if you want: create specialized cells with unique identifiers for each, and then return the cell heights that go with them. if you take this route, then you may be able to get away with just using dequeueReuaableCellWithIdentifier and using the height value for that identifier. just use a unique cell identifier with a height that's appropriate for each cell you're thinking of.
The default height of cell is 44 .. so you can return it when your condition is not satisfied ..
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (YOUR_SPECIFIC_CONDITION) {
return 180.0;
}
return 44.0;
}
May this will help you..
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0 && indexPath.section==0)
{
return 180.0;
}
else
{
return 44.0;
}
}

Resources