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
Related
I have a section with dynamic multiple rows and I need to separate all the section with the background as shown in the image below.
Specifically those border lines for all the section. Pease let me know how can I make it possible.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
{
return ProductArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *arr = [ProductArray objectAtIndex:section];
return arr.count;
}
Please refer to this
.
I tried adding header and footer, But I am not understanding how to add that rectangle box image for the entire section.
Put View in your cell after make outlet of that view. And use to cellForRowAtIndexPath this method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.viewBackGround.backgroundColor = [UIColor redColor];
return cell;
}
For above requirement, I would like to suggest you the below approach.
create only one section with multiple rows.
Each row of UITableView will have UITableViewCell
Inside UITableViewCell create content view for which we are gonna add the border
Each row of UITableViewCell will have another UITableView(inside content view) whose methods are handled by UITableViewCell cells
Change UITableView (inside) height based on number of rows.
provide height of UITableViewCell based on the number of rows + orderID Header.
I have created custom cells in my app.I want to get the each cell in HeightForRowAtIndexPath.Please tell me how can i get the custom cell in this method.I have tried this code but this causes infinite loop & finally crash the app.
HomeCell *cell=(HomeCell *)[tableView cellForRowAtIndexPath:indexPath];
EDIT:
I Have tried this but it gives me cell height as zero.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"HomeCell";
HomeCell *cell = (HomeCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
float tv_view_height=cell.tv_post.frame.size.height;
float like_count_height=cell.label_like_count.frame.size.height;
float first_comment_height=cell.first_comment.frame.size.height;
float second_comment_height=cell.second_cmment.frame.size.height;
float third_comment_height=cell.third_comment.frame.size.height;
Post *user_post=[arr_post objectAtIndex:indexPath.row];
float comment_count=[user_post.comment_count intValue];
if(comment_count<=0)
{
first_comment_height=0;
second_comment_height=0;
third_comment_height=0;
}
else if(comment_count==1)
{
second_comment_height=0;
third_comment_height=0;
}
else if(comment_count==2)
{
third_comment_height=0;
}
float like_count=[user_post.like_count intValue];
if(like_count<=0)
{
like_count_height=0;
}
float total_height=tv_view_height+like_count_height+first_comment_height+second_comment_height+third_comment_height;
NSLog(#"total heigh is %f'",total_height);
return total_height;
}
Please tell which is the best way?
How to get cell in heightForRowAtIndexPath?
It's impossible, because when -heightForRowAtIndexPath is called, no cells are created yet. You need to understand how the UITableView works:
UITableView asks it's datasource how many sections it will have
-numberOfSectionsInTableView
At this point there are no cells created.
UITableView asks it's datasource how many rows each section will have
-numberOfRowsInSection
At this point there are no cells created.
UITableView asks it's delegate height of each visible row, to know where cells will be located
-heightForRowAtIndexPath
At this point there are no cells created.
UITableView asks it's datasource to give it a cell to display at given index path
-cellForRowAtIndexPath
At this point the cell is created.
The height of each cell you can calculate from data model. You don't need the cell – you already know the frame width that will contain a comment, you know it's content, you know it's font, you know linebreak mode, etc. So, you can calculate height. For example:
CGFloat commentsHeight = 0;
Post *user_post = [arr_post objectAtIndex:indexPath.row];
for (NSString *comment in user_post.comments)
{
CGRect commentrect = [comment boundingRectWithSize:CGSizeMake(self.view.bounds.size.width - 18, FLT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin)
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:15]}
context:nil];
commentsHeight += commentrect.size.height;
}
And you can calculate height of the other components of cell from its data model.
But now, in 2015, it's not the best way. You really would be better to read the tutorials, which showed #Zil, and do it with Autolayout.
You should declare an array for storing TableView cells in cellForRowAtIndexPath and you can use stored cells in heightForRowAtIndexPath. Lets Try using this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"HomeCellID";
HomeCell *cell = (HomeCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[[HomeCell alloc] init] autorelease];
}
// Store table view cells in an array
if (![tableViewCells containsObject:cell]) {
[tableViewCells addObject:cell];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([tableViewCellsArray objectAtIndex:indexPath.row]) {
HomeCell *cell = (HomeCell *)[tableViewCells objectAtIndex:indexPath.row];
// Process your Code
}
return yourCalculatedCellHeight;
}
I would recommend you to take the height form a configuration collection on your viewController.
Something like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height;
CellConfiguration * selectedCellConfiguration =[_cellConfigurations objectAtIndex:indexPath.row];
switch (selectedCellConfiguration.type) {
case TheTypeYouNeed:
return TheValueYouNeed
default:
height = 44.0f;
break;
}
return height;
}
You could create a new cell from scratch, simply by HomeCell *sexyCell = [[HomeCell alloc]init];
or dequeue one like you did in cellForRow (tableView.dequeueWithReuseIdentifier:).
Though I advise creating one from scratch and disposing it after (setting it to nil), because if you dequeue it there they'll go in queue and cause heavy memory leaks and end up with many cells for the same indexPath.
What you COULD do is the following :
Create a cell with alloc init
Fill it with the real data
use .layoutsubviews on its view
calculate it's size and apply it to your real cell
What you SHOULD do :
Use auto layout and add all the constraints that are necessary, all your labels will size dynamically. It takes about 3 or 4 hours to get the basics of Auto layout, and about a month of regular use to really get the hang of it with ease.
I strongly strongly strongly suggest you do NOT resize using the frame of objects, most labels and views will resize like they should without having to write any code if you use constraints properly.
Once you have done that, because you have cells of varying heights, is using the DynamicHeight property of the tableview and the slight adjustements that comes with it. You can find
A great tutorial here
The same updated tutorial for swift (more up to date but you'd need to translate)
This amazing StackOverflow answer which you MUST read
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:indexpath.row inSection:0];
Custom Cell *cell = [tableview cellForRowAtIndexPath:indexPath];
By this , you will get each cell in your method
I have a table view and I want to include margins so that the table's content has some breathing room on the left and right, and also between cells.
I managed to do a table view like:
My Storyboard design is like:
What I did was I added a UITableView to the main view and gave a margin of 10. I added constraints as shown in figure. Changed the Seperator style to None.
Then I added two UITableViewCells.
For Holding the data with custom row height 70.0
Row with same background of parentView with custom row height of 10.0
And implemented the methods like below:
// Row count (Twice as needed, for showing the insect)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 15*2;
}
// Returns cell based on indexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
// Decides whether content or inset
if (indexPath.row%2)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"ReuseInset"];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:#"ReuseMe"];
cell.textLabel.text = #"MMP";
}
return cell;
}
// Returns custom row height based on indexpath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{ if (indexPath.row%2)
{
return 10.0;
}
return 70.0;
}
Because using three labels over UITableViewCell slowed down tableview scroll performance I tried drawing directly on UIView that I dragged over the prototype cell. While this significantly improved scroll performance, this got me into another problem.
Actually I am drawing the contents of a feed. After six or seven unique rows (for 20 records), rows are duplicate. They show the same content starting from top of tableview. However When I tap on those repeated cells the content changes to what it should have been.
After researching I found six or seven is the number of rows actually visible on the screen. So this should have been display update error but I am not sure should I do to fix this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"newsCell";
NewsCell *cell = (NewsCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (indexPath.row < feeds.count) {
dict = [feeds objectAtIndex:indexPath.row];
[cell setNewsHeading:[dict objectForKey:#"title"] pubDate:[dict objectForKey:#"pubDate"] newsExcerpt:[dict objectForKey:#"attributedDescription"]];
}
dict = nil;
return cell;
}
-(void)setNewsHeading:(NSString *)newsHeading pubDate:(NSString *)pubDate newsExcerpt:(NSAttributedString *)newsExcerpt
{
self.newsView.newsHeading = newsHeading;
self.newsView.pubDate = pubDate;
self.newsView.newsExcerpt = newsExcerpt;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [feeds count];
}
That sounds like it could be a caching issue - have you tried overriding the prepareForReuse method in your cell subclass to reset the cell contents back to the default values?
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;
}