In a single UiView controller class i've added 3 UITableView.
UITableView *ChaptersTableView;
UITableView *SubChaptersTableView;
UITableView *SubTopics1TableView;
Now in ViewDidLoad of class i've initialized these TableView's & calling the Delegate & Datasource methods on these Table View's.
ChaptersTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
ChaptersTableView.delegate=self;
ChaptersTableView.dataSource=self;
SubChaptersTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
SubChaptersTableView.delegate=self;
SubChaptersTableView.dataSource=self;
SubTopics1TableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
SubTopics1TableView.delegate=self;
SubTopics1TableView.dataSource=self;
I wish to have different content & height for rows of different Table views. For eg. TableView1 will have cell height of 20, TableView2 will have cell height of 40 & TableView3 will have cell height of 60.
So how do i go about customizing these delegate & datasource methods depending on the tableView they are called for?
Thanks.
The delegate methods return the tableview object. Hence while creating you can tag the tableviews like this. SubTopics1TableView.tag = 0, SubChaptersTableView.tag = 1 etc.
In your delegate methods check the tag and configure the tableviews.
For eg
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableview.tag == 0)
// Customise this tableview
}
To change how the cell will look you can use the delegate method:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
To change the height of the row you can use:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Have a look at this code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *cellIden = nil;
UITableViewCell *cell = nil;
if( [mTableView1 isEqual:tableView ])
{
cellIden = #"Cell1";
cell = [tableView dequeueReusableCellWithIdentifier:cellIden];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIden];
}
cell.textLabel.text = [mList objectAtIndex:indexPath.row];
}
if( [mTableView2 isEqual:tableView ])
{
cellIden = #"Cell2";
cell = [tableView dequeueReusableCellWithIdentifier:cellIden];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIden];
}
cell.textLabel.text = [mArray objectAtIndex:indexPath.row];
}
return cell;
}
assign tag to each table ....
-(CGFloat )tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if(tableView.tag==1)
return 20;
else if(tableView.tag==2)
return 40;
else if(tableView.tag==3)
return 60;
}
To modify a cell's height you have to implement the tableView:heightForRowAtIndexPath: in the delegate class, not the data source. You can attach the same delegate to all the three tables and implement that method this way:
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if ([tableView kindOfClass:[ChaptersTableView class]])
return 20;
else if ([tableView kindOfClass:[SubChaptersTableView class]])
return 40;
else if ([tableView kindOfClass:[SubTopics1TableView class]])
return 60;
else return 44;
}
This solution will work if you plan to use different tables with different, but unique, classes. If you plan to differentiate the cell's height for two different tables that implement the same class (eg class of tableView1 == class of tableView2 == Class1), you should set a different flag in that class' implementation and test for that flag's value.
Let me know if this can help
Related
I am becoming increasingly frustrated as I can not figure out how to get this to work.
I have searched and searched and nothing seems to be helping me out to get this to do what I want.
What I am trying accomplish: I am trying to get the Task that the user will type in using the UITextField on top to add a new cell with their input as the text and with a check box to the left of it. When the cell is tapped, I would like to have the check box change to one with a check mark within it and for the entire cell to change opacity to 50%. Also, I would like to make the cell pop up with a delete button when it is swiped from left to right.
How would I make this all happen? I currently just have the UITextField added to the .xib using the Attribute Inspector to make it look the way it does. I also have a tool bar up top that I have used the Attributes Inspector to modify as well.
Nothing is coded to connect these to actions, they are just sitting in the .xib.
Here is an image of the rendering I created. (What I am trying to get)
http://i.imgur.com/rTKnvud.png
Here is what I have so far in Xcode in the .xib.
http://i.imgur.com/wfcVOrY.png
Thank you in advanced,
Jacob
You need to either add button to cell programatically or create a custom cell. When user taps on cell or checkbox you can change button's image to selected checkbox. for proper display of checkbox take a NSMutableArray and use the below code.
Note
1. specialNeedsList is a array which I'm using to display data on cell.
2. selectedSpecialNeed is a Mutable Array which I'm using to store selected/checked values
3. I'm using checkbox button for UITableViewCell accessory view. IN your case code will be little bit different.
Follow this tutorial Get row for button tapped as well along with my code. You will get idea for accomplish this. Whatever I'm doing on - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
you need to do this on UIButton's action.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger returnValue = 1;
return returnValue;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger returnValue = 0;
returnValue = ([self.specialNeedsList count] > 0) ? [self.specialNeedsList count]:0;
return returnValue;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
UIButton * btnShare = [[UIButton alloc] initWithFrame:CGRectMake(0,0,30,30)];
[btnShare setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[btnShare setImage:[UIImage imageNamed:#"checkboxChecked.png"] forState:UIControlStateHighlighted];
[btnShare setImage:[UIImage imageNamed:#"checkboxChecked.png"] forState:UIControlStateSelected];
[btnShare addTarget: self action: #selector(accessoryButtonTapped:withEvent:)
forControlEvents: UIControlEventTouchUpInside];
cell.accessoryView = btnShare;
[btnShare release];
}
NSString* subAreaOfStudy = [self.specialNeedsList objectAtIndex:indexPath.row];
if (self.specialNeedsList && [self.specialNeedsList count] > 0) {
[cell.textLabel setFont:[UIFont systemFontOfSize:15.0f]];
cell.textLabel.text = [self.specialNeedsList objectAtIndex:indexPath.row];
}
BOOL isShared = ([self.selectedSpecialNeeds count] > 0 && ([self.selectedSpecialNeeds indexOfObject:subAreaOfStudy] != NSNotFound));
UIButton* btnShare = (UIButton*)cell.accessoryView;
btnShare.selected = isShared;
[btnShare setNeedsDisplay];
return cell;
}
- (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event{
NSIndexPath * indexPath;
indexPath = [tblVSpecialNeeds indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView:tblVSpecialNeeds]];
if ( indexPath == nil )
return;
[self tableView:tblVSpecialNeeds accessoryButtonTappedForRowWithIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
NSString *draft = [self.specialNeedsList objectAtIndex:indexPath.row];
BOOL recordAlreadySelected = ([self.selectedSpecialNeeds indexOfObjectIdenticalTo:draft] != NSNotFound);
if(recordAlreadySelected) {
[self.selectedSpecialNeeds removeObject:draft];
}
else {
[self.selectedSpecialNeeds addObject:draft];
}
[tblVSpecialNeeds reloadData];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row > [self.specialNeedsList count]-1) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
return;
}
[self tableView:tblVSpecialNeeds accessoryButtonTappedForRowWithIndexPath:indexPath];
}
To delete on swipe, use Tableview's Delegate method:
(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
[arrAddData removeObjectAtIndex:indexPath.row];
[tbldata reloadData];
I have 3 table views in one view and I was wondering why the tableView:cellForRowAtIndexPath: was not getting called.
#pragma mark -
#pragma mark <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.mainVoucherTableViewController)
[self setSelectedIndex:indexPath.row];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.mainVoucherTableViewController){
return 10;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.mainVoucherTableViewController){
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.textLabel.text = #"THISTEXT";
return cell;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == self.mainVoucherTableViewController)
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// The header for the section is the region name -- get this from the region at the section index.
if (tableView == self.mainVoucherTableViewController){
NSString * myString = [NSString stringWithFormat:#"HELLLO WORLD"];
return myString;
}
}
WOULD anyone know why this is? Basically this doesn't create any cell or display cells. It just displays the table views. :(
Just to consolidate a few things from above:
From your naming, your tableView is called mainVoucherTableViewController - just want to confirm that this is indeed a UITableView and not a UITableViewController? If it's a UITableViewController then the rest of this won't work for obvious reasons (or not so obvious - let me know and can explain further)
Make sure you have set the current viewController as the tableView's delegate and dataSource, either with the code below or in Interface Builder if you're using a XIB
self.mainVoucherTableViewController.delegate = self;
self.mainVoucherTableViewController.dataSource = self;
Make sure your numberOfRowsInSection function is being called and that you're returning non-zero (put in NSLogs, etc) and do the same for numberOfSections as well (actually numberOfSections isn't required if you're only using 1 section) - see UITableViewDataSource Protocol Reference: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html
As per previous post, log your cellForRow (if points #1-3 are checked and working) at the beginning to make sure it's triggered, and just before the return. Also do an NSLog of the cell you're returning just to make sure it isn't nil.
Start off by logging inside your tableView:cellForRowAtIndexPath: method to see if it gets called at all outside your if statement as well as inside to help narrow down the issue.
Also try instead of comparing your:
tableView == self.mainVoucherTableViewController
Set the tableViews to have tag values instead. Then you can do:
if(tableView.tag == 100){ // tag number we assigned self.mainVoucherTableViewController via IB
//do your stuff here
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.mainVoucherTableViewController)
{
return 10;
}
else
{retun 5;
}
}
It display row in first table 10, second table show 5 rows.
The order of instance declaration does matter. For example, if you have a ivar called tableView:
WRONG
self.tableView.delegate = self;
self.tableView = [UITableView alloc] init];
CORRECT
self.tableView = [UITableView alloc] init];
self.tableView.delegate = self;
check UITableView Object Frame Size. maybe Frame size is not enough to draw Cell.
Is there a way to combine static tableview cells (static content) with dynamic tableview cells (prototype content) using storyboard?
I suggest you treat your table as dynamic, but include the cells you always want at the top. In the Storyboard, place a UITableViewController and have it use a dynamic table. Add as many UITableViewCell prototypes to the table as you need. Say, one each for your static cells, and one to represent the variable cells.
In your UITableViewDataSource class:
#define NUMBER_OF_STATIC_CELLS 3
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dynamicModel count] + NUMBER_OF_STATIC_CELLS;
}
and, then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < NUMBER_OF_STATIC_CELLS) {
// dequeue and configure my static cell for indexPath.row
NSString *cellIdentifier = ... // id for one of my static cells
} else {
// normal dynamic logic here
NSString *cellIdentifier = #"DynamicCellID"
// dequeue and configure for [self.myDynamicModel objectAtIndex:indexPath.row]
}
}
I had a problem, although it was a slight variant of this. I actually wanted to mix dynamic and static cells but in different groups. Meaning group 1 would have static only cells and group 2 would have dynamic cells.
I accomplished this by actually hard coding static cell values (based on their prototype cell identifiers). The dynamic sections would have normal dynamically populated content. Here is some example code in case anyone else has the same issue:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == 1){
return #"Dynamic Cells";
}
if (section == 0){
return #"Static Cells";
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return 1; //However many static cells you want
} else {
return [_yourArray count];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 0) {
NSString *cellIdentifier = #"staticCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = #"some static content";
return cell;
} else if (indexPath.section == 1){
NSString *cellIdentifier = #"dynamicCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [_yourArray objectAtIndex:indexPath.row];
return cell;
}
return nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
Since no one has actually provided a real answer to the problem (using both static and prototype cells in the same table view), I figured I'd chime in.
It can be done!
Create your static cells as you see fit.
For the sections that need a dynamic cell, if you are NOT using standard UITableViewCell type, you'll need to create your custom one in a separate Nib, otherwise you can use the standard ones.
Then implement the following delegates. Basically for each of these delegates, for the static stuff we want to call super, for the dynamic, we return our values.
First, IF you need to selectively show your dynamic section, you'll want to implement the numberOfSectionsInTableView (otherwise you can leave this delegate out):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int staticSections = 1;
int dynamicSections = 1;
if (SOME_BOOLEAN) {
return staticSections + dynamicSections;
} else {
return staticSections;
}
}
Then, you need to implement numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 1) {
return A_COUNT;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
Then, you need to implement heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 44.0f;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
Then indentationLevelForRowAtIndexPath:
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 1; // or manually set in IB (Storyboard)
} else {
return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath]; // or 0
}
}
Finally, cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
SomeObject *obj = self.someArray[indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"DynamicCell" forIndexPath:indexPath];
cell.textLabel.text = obj.textValue;
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
You can always make one you your tableviews appear similar to the static table but define it in code. Set the sections, amount or rows per section, headers etc. through the delegate methods.
Unfortunately, this is not possible since static table views must be in a UITableViewController and that only allows one tableview.
What you need to do is make three more dynamic UITableviewCell's and load them individually for the first three rows where you want the static content.
If you aren't sure how to do this, let me know and I can find some code.
You can't have one tableview be static and the other dynamic in the same view controller so you will need to make them both dynamic. In the first tableview you will configure the cells in code on initializing the view controller never update them.
Add a UIViewController to your storyboard.
Add two Table Views (Not
TableViewControllers) to the UIView Controller.
Select each tableView and configure both for dynamic cells.
Build and attach your view controller. 2 tableview on a single view explains that step.
As another option you can achieve a similar look by embedding your dynamic tableview in part of a view similar to the link in step 4 and then do whatever you wanted to in the rest of the view to setup what you were planning to do with static cells by using scrollviews, labels, and buttons.
You could also create buttons (one for each static cell you have) that are styled like your cells and place them in the tableHeaderView or tableFooterView of the UITableView; those buttons are just views after all.
You'll need to add some logic for making selections on the buttons vs. the cells so it maintains the usual look and feel.
Of course, this assumes that you want to insert static cells into your table view at the top or bottom of the table.
One way to have dynamic content in a static table view is to clone cells where additional rows are needed.
For the dynamic section of my table view, I lay out one or more cells in Interface Builder. At runtime, I can clone those by archiving using NSCoder and then unarchiving.
It works, but is not necessarily prettier than starting with a dynamic prototype table view and creating static rows from there.
It fails with standard table view cells. The lazily created text labels are not laid out correctly. Hence I used UITableViewCell subclasses where I take care of archiving and unarchiving subviews.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == kContactsSection) {
NSArray *contacts = self.contacts;
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *name = contact.name;
NSString *role = contact.role;
if ([role length] == 0) {
NNContactDefaultTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : #"contactDefault"];
if (cell == nil) {
NNContactDefaultTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
return cell;
}
else {
NNContactDetailTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : #"contactDetail"];
if (cell == nil) {
NNContactDetailTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:1 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
cell.contactDetailTextLabel.text = role;
return cell;
}
}
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
In the above example I have two cell types. Both laid out in Interface Builder as part of a static table view.
To get dynamic content in one section, I also need to override the following methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == kContactsSection) {
NSArray *contacts = self.contacts;
NSUInteger contactCount = [contacts count];
return contactCount;
}
return [super tableView:tableView numberOfRowsInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if (section == kContactsSection) {
return [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
}
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
if (section == kContactsSection) {
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
return indentation;
}
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
return indentation;
}
I setup my cells like this:
So, a couple of switches, define the cells, because the data is not in the list of objects, but a set of information which should be displayed in a tableView in some different ways.
-(UITableViewCell *)value1CellForTableView:(UITableView *)tableView {
static NSString *CellIdentifierValue1 = #"Value1Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierValue1];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifierValue1];
cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
cell.textLabel.textAlignment = UITextAlignmentLeft;
}
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
switch (indexPath.section) {
case 0:
//Coupon
switch (indexPath.row) {
case 0:
//Couponcode
cell = [self value1CellForTableView:tableView];
cell.textLabel.text = #"Code";
cell.detailTextLabel.text = presentedCoupon.couponNr;
break;
case 1:
//Coupondescription
cell = [self value1CellForTableView:tableView];
cell.detailTextLabel.text = presentedCoupon.couponDescription;
cell.detailTextLabel.numberOfLines = 0;
cell.textLabel.text =#"Ihr Vorteil";
break;
}
break;
case 1:
//Productinfo
switch (indexPath.row) {
case 0:
cell = [self defaultCellForTableView:tableView];
cell.imageView.image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: [presentedCoupon.refProdName stringByAppendingString:#".png"]]];
cell.textLabel.text = presentedCoupon.refProdName;
break;
}
break;
case 2:
//Shopinfo
switch (indexPath.row) {
case 0:
cell = [self defaultCellForTableView:tableView];
cell.textLabel.text = ((Shop*)presentedCoupon.refShop).name;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
break;
}
break;
}
if (cell == nil) {
cell = [self defaultCellForTableView:tableView];
cell.textLabel.text = #"Stanni";
}
[cell layoutIfNeeded];
return cell;
}
And i calculate the height like this.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"height");
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat height = 24 + [cell.detailTextLabel.text sizeWithFont:cell.detailTextLabel.font constrainedToSize: CGSizeMake(cell.detailTextLabel.frame.size.width, 1000.0f) lineBreakMode:cell.detailTextLabel.lineBreakMode].height;
return MAX(height, 44.0f);
Problem:
The problem is, as mentioned in many threads, and also visible in my log, that the height of each cell, (visible or not) is asked at the initialization of the table view. So in bigger 100+ lists, also 100+ cells are created --> wasted at startup.
Ist there another possibility to get this information when the cell is set up like this? Is it really neccessary to built the switch case sturcture again in heightForRowAtIndexPath to avoid these calls and though get the right heights for each cell?
Would it be better to hold a "datasource-list" with the single information of each cell?
But how to handle the different cell styles, custom cells.
The method
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
is called for each cell before the method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
So in the first method, cells are not yet created, and you should not try to access them.
When you create a tableView, the data source is first asked for the number of row. Then for each row, the data source is asked for the height of the row, so that the tableView know the total height of it's content, and then finally, the data source is asked for the cell (actual view) to display.
In your case, i would built the switch case structure again. Concerning the "datasource-list", I have never done it before, so maybe it's a better solution.
Two possibilities:
How many cells you have? If you have a small number of cells (which seems to be the case here), you don't need cell reusing! In general, cell reusing is overused.
Just create cells when you are creating your controller or when you have updated your data and put them into a NSArray.
Then you can return them from tableView:cellForRowAtIndexPath: or measure their height.
Create a separate method that returns cell text/font and use it in both delegate methods instead of reading the information from the cell directly.
If you have an array of strings in objects and are using the standard table cell then try this iOS 7 compatible magic:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString* text = [self.objects objectAtIndex:indexPath.row];
NSAttributedString * attributedString = [[NSAttributedString alloc] initWithString:text attributes:
#{ NSFontAttributeName: [UIFont systemFontOfSize:18]}];
//its not possible to get the cell label width since this method is called before cellForRow so best we can do
//is get the table width and subtract the default extra space on either side of the label.
CGSize constraintSize = CGSizeMake(tableView.frame.size.width - 30, MAXFLOAT);
CGRect rect = [attributedString boundingRectWithSize:constraintSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
//Add back in the extra padding above and below label on table cell.
rect.size.height = rect.size.height + 23;
//if height is smaller than a normal row set it to the normal cell height, otherwise return the bigger dynamic height.
return (rect.size.height < 44 ? 44 : rect.size.height);
}
As I see – you have only two cell types.
So you might have a #property for each type of cell (please take a look to an example below):
static NSString * const kCellIdentifier = #"kCellIdentifier";
#interface ...
#property (nonatomic, retain) UITableViewCell *cell;
#end
#implementation
#synthesize cell = cell_;
...
- (UITableViewCell *)cell {
if (!cell_) {
cell_ = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kCellIdentifier];
}
return cell_;
}
- (UITableViewCell *)cellForTableView:(UITableView *)tableView {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
if (!cell) {
//put it to autorelease pool to avoid EXC_BAD_ACCESS
cell = [[self.cell retain] autorelease];
self.cell = nil;
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = self.cell;
CGFloat height = 24 + [#"text" sizeWithFont:cell.detailTextLabel.font constrainedToSize: (CGSize){cell.detailTextLabel.frame.size.width, CGFLOAT_MAX} lineBreakMode:cell.detailTextLabel.lineBreakMode].height;
return MAX(height, 44.0f);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self cellForTableView:tableView];
cell.detailTextLabel = #"text";
return cell;
}
So the cell would be initialized only once in the beginning.
I have a xib with a view which contains two views which each contain a tableview shortened in height. The root view has a segmented controller which should toggle the views. How can I make each tableview point to it's appropriate class?
One way to do it is to add two UITableViewController classes to your project from File->Add, then click on Include Xib option. This will create the two table views xib files along with. You can then init the two controllers while in your main controller's ViewDidLoad event, and assign them a frame that is equal to the left & right views you have as follows:
[firstTableController.view setFrame:rightView.frame];
[secondTableController.view setFrame:leftView.frame];
Where both rightView & leftView are UIView * objects that are hooked to your two views in IB.
You can then simply add the two table controllers to your main view controller using addSubView from the main controller:
[self.view addSubView:firstTableController.view];
[self.view addSubView:secondTableController.view];
Hope this helps.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int x;
if (tableView.tag == 100)
{
x = [tab1 count];
}
if (tableView.tag == 101)
{
x = [tab2 count];
}
return x;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Helllo";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if (tableView.tag ==100)
{
cell.textLabel.text= [tab1 objectAtIndex:indexPath.row];
}
if (tableView.tag == 101)
{
cell.textLabel.text=[tab2 objectAtIndex:indexPath.row];
}
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
tab1 and tab2 are arrays.