I want a custom look for my UITableView with images for the header, footer and cells. For that matter, I return a UIImageView for the header and footer of the table, and I also set a UIImageView as the backgroundView of the cells.
The problem is that image of the cells is narrower than the header/footer. This seems to be the default behavior of the grouped style of UITableView. I need a grouped style so that the header won't overlap with the cells when scrolling.
Is there any way around this problem?
sorry my poor english, i could understend you wrong. But if there was not mistake:
if you will not find "right" solution, you may try this:
(this is not the best way to do what you whant, but it is the only one I can offer)
all you need is make your table view with only ONE section, without header. Then, just make every "raw" wich must be header of anothe section with different parameters:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return <number of all raws in all sections plus number of sections, to make some raws - sections>;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
for (int i = 0; i < (number of sections); i++) {
if (indexPath.raw == i*(number of raws in section i)) return (heigth of header);
}
return (heigth of raw);
}
//Configure cells:
- (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];
}
// Configure the cell...
for (int i = 0; i < (number of sections); i++) if (indexPath.raw == i*(number of raws in section i)) {
//set properties to headers
return cell;
}
//set properties to raws
return cell;
}
Related
I had one table view in which I had 15 row in one section.
so when the table view get loaded it shows only first 9 rows, I checked it with method CellForRowAtIndexpath method but I want to get all 15 rows to be get called in this method for the viewload method.
please help me on out.
thanks in advance....
it depends how much rows you set from
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
if you have an array then return
[arr count]; as number of rows and if you want static rows then use return 15; in this method
You use these method or if you want all your cell on front of first time view then you should decrease the height of the cell using last method.And also check your array how much values he have.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [Array count];
}
-(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];
}
cell.textLabel.text=[Array objectAtIndex:indexPath.row];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 20;//use this method for cell height
}
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;
}
Can anyone tell me that how to remove all rows of a tableView
Clear the datasource (for example [dataSourceMutableArray removeAllObjects]) and reload the table ([tableView reloadData])
I think you can remove all values in dataSource of tableView? Then reload the tableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 0;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
or specify return nil; instead of return cell; in cellForRowAtIndextPath function
or you can remove all values in array in cellForRowAtIndexPath like this
- (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];
}
// Configure the cell.
// remove below line
//cell.textlabel.text=[array objectAtIndex:indextPath];
return cell;
}
i have been trying to figure this out but i just can't....
for some reason, everytime my UITableView reaches a certain length due to the number of rows and sections, cells seem to randomly copy themselves into different cells at the end of the table without me wanting or programming it... Anyone else have this issue or knows how it's resolved? Any help is appreciated! Tanks.
Edit:
The "row" property is a counter which gets counted up to 13 and is then reset to 0 and counted up again and i always want the string "newUpdate" to be displayed in the corresponding row but at the same time i don't want the rest of the cells to be blank i want them to keep their old content until they're overwritten because the counter is starting at 0 again.
#import "ServerUpdateViewController.h"
#implementation ServerUpdateViewController
#synthesize newUpdate;
#synthesize row;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 15;
}
- (NSString *)tableView: (UITableView *)table titleForHeaderInSection:(NSInteger) section {
return #"All Updates to Server";
}
// Customize the appearance of table view cells.
- (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];
}
if (indexPath.row == self.row) {
cell.textLabel.text = self.newUpdate;
}
// Set up the cell...
return cell;
}
- (void)dealloc {
[super dealloc];
}
#end
You're re-using cells. In your cellForRowAtIndexPath: method, you need to fully configure the cell every time it's called.
There are a few things that can cause this and I can't be specific without seeing code, but it comes down to the fact that cells are reused. The entire content of the cell will have to be re-set/redrawn every time cellForRowAtIndexPath is called.
I have a grouped tableview that is populated with XML data in one section. What I would like to do is create another section prior to the data driven one, and apply an action to it.
Example:
The user is presented with a button that says "use your current location" (manually created section) and below that is a list of countries the user can alternatively choose from choose from (data driven section)
Use the settings menu as a guide. There are some options which are a single row in a section, so they appear to be a button...
If this doesn't make sense, I will try to explain it better.
So I have these two obvious lines of code...simple enough
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [countrysData count];
}
What I would like is to have numberOfSectionsInTableView return 2 and have the first "Section" say "Click to use your current location" which would then push into view a map, and the second section display the list of countries I currently have working.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0){
return 1;
}else{
return [countrysData count];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
then you should choose what to do in your didSelectRowAtIndexPath: method due to the indexPath.section. oh, and you should check indexPath.section in your cellForRowAtIndexPath: method.
You just need to update all of your implementations of the UITableViewDataSource and UITableViewDelegate protocols to appropriately account for the new section and its row(s).
For example, here's how to update numberOfSectionsInTableView:, tableView:numberOfRowsInSection:, and tableView:cellForRowAtIndexPath:, but you will want to update at least tableView:didSelectRowAtIndexPath: as well:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// calculate the number of sections of non-data (might just be 1)
// calculate the number of sections for the data (you were already doing this, might just be 1)
// return the sum
return 1 + 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger rowCount = 0;
switch (section) {
case 0:
// non-data section has 1 row/cell
rowCount = 1;
break;
case 1:
// data section uses an array
rowCount = [dataArray count];
break;
}
return rowCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *nonDataCellID = #"NonDataCell";
static NSString *dataCellID = #"DataCell";
UITableViewCell *cell;
int section = [indexPath indexAtPosition:0];
int row = [indexPath indexAtPosition:1];
switch (section) {
case 0:
// or you can just use standard cells here
cell = [tableView dequeueReusableCellWithIdentifier:nonDataCellID];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"NonDataCell" owner:self options:NULL];
cell = nonDataCell; // nonDataCell is an IBOutlet to this custom cell
}
// configure non-data cell here (use tags)
UILabel *someLabel = (UILabel*)[cell viewWithTag:1];
someLabel.text = #"Non-data cell";
break;
case 1:
// or you can just use standard cells here
cell = [tableView dequeueReusableCellWithIdentifier:dataCellID];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"dataCell" owner:self options:NULL];
cell = dataCell; // dataCell is an IBOutlet to this custom cell
}
// configure data call here (using "row")
UILabel *someDataLabel = (UILabel*)[cell viewWithTag:1];
someDataLabel.text = [[dataArray objectAtIndex:row] valueForKey:#"name"];
break;
}
return cell;
}
I'm pretty sure you can alter the return of UITableViewDataSource's method 'numberOfSectionsInTableView:' on the fly. Once the user selects the choice of an additional section, just set a flag to have the method return the number of tables you want. Then you force a reload of the table and you should see the new section.