allow editing in uitableview, but not in one row - ios

I have a UITableView with multiple sections. When I set the table into edit mode, then I would prefer that one section (which only includes 1 row) does not display the edit symbol and not call tableView:commitEditingStyle:forRowAtIndexPath:.
Is this possible?
regards
John

here i assume for section 1 and row 0 which can not edit
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
if (indexPath.section == 1) {
if (indexPath.row == 0) {
return NO;
}
}
return YES;
}

Related

UITableView showing inconsistent number of rows compared to data source

I'm trying to make a UITableView present a determined number of rows for a section, but even when I verify that its data source is returning x number of rows for numberOfRowsInSection, the table view shows x-1.
The exception to this unexpected behavior is if the numberOfRowsInSection is less than 3.
I've even put a breakpoint in cellForRowAtIndexPath and I confirmed it's being called for the row that is not appearing.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == SectionNumber_One) {
return 6;
} else {
return self.numberOfProjectRows; // This returns x, but x-1 rows are being shown
}
}
For example, if self.numberOfProjectRows is 5, only 4 rows are shown for the second section.
If I increase it manually to 6, it shows 5 rows but the data that should be in the 5th position, isn't there.
It doesn't seem to be related to screen size as I tested it on an iPad with same results.
Why is this happening? Is there some other possible modifier of the number of rows in a section?
I'm attaching an screenshot if it's of any help.
EDIT - Here are my delegate methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Cell with reuse identifier setup
if (section == SectionNumber_One) {
// cell setup for section one that's showing up ok
} else if (section == SectionNumber_Two) {
UITextField *projectField = cell.projectTextField;
if ([self.userProjectKeys count] > row) {
projectField.text = self.availableProjects[self.userProjectKeys[row]];
}
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Hide the password row for existing users
if (indexPath.row == FieldTag_Password && ![self.user.key vol_isStringEmpty]) {
return 0.0f;
} else {
return UITableViewAutomaticDimension;
}
}
The problem is probably not in your Datasource methods, but your Delegate methods, tableView(_:heightForRowAt:).
If you do not return a correct height for the cell, it won't show up.
It doesn't matter if you write 1000 cells in your datasource. If you don't return the height, they wont show up.
You are not comforming to the MVC pattern in implementing the table. You must return the count of the tableView's datasource, not variables of it.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == SectionNumber_One) {
return 6;
} else {
return [_displayingArray count]; // <-- here
}
}
If you want different items for each sections, then declare different datasource (ie array) for each of them.
EDIT: Even returning constant 6 is dangerous in the other section - you ought to add items to another fixed array and return that array's count in this delegate.

Index Section in viewForHeaderInSection

i have UITableView header custom like Instagram where my section acts header, in this tableview i also using paging to get the data from server.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (currentPage == 0) {
return 1;
}
if (currentPage < totalPages) {
return myObject.count+1;
}
return myObject.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 1;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection (NSInteger)section
{
myTimeline = [myObject objectAtIndex:section];
//the rest of my code to display text in UILabel cell, etc
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.tag == kLoadingCellTag) {
currentPage++;
[self getTimeline];
}
}
Now the problem is, I already make sure that my paging is working and myObject array count is increase.
But when i do the scroll it crash in method viewForHeaderInSection with reason "index 10 beyond bounds [0 .. 9]'" (i set the paging in in server with 10 items per page)
I think the section in ViewForHeaderInSection not updating with numberOfSectionsInTableView method that i already setup.
So how to make the section in ViewForHeaderInSection updated?
Thanks..
Your numberOfSectionsInTableview has return myObject.count+1;, so the table view is dutifully asking for the header for the last section, which is beyond the bounds of your myObject array. You need either to remove the +1 or, if it's there for a reason, to include code in viewForHeaderInSection to handle that special case:
if (currentPage > 0 && currentPage < totalPages && section == myObject.count) {
// create whatever header view is appropriate for the final section
} else {
myTimeline = ... etc
}

Show a table view footer on only one section

I am developing an app that lists products. The products are section headers. If you tap on a product it expands to show that sections' table, with modifications for that product in cells of that table.
What I want to do is have a footer for each section that will have an 'Add to Cart' button. That footer should only be visible when the product is expanded. If I use this:
- (CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section {
if (self.isOpen) {
return 35.0;
}
else {
return 0.0;
}
}
The footer doesn't show on any product section until you select a product, then it is visible on all products. Is there a way to have it a certain height on only one table section? I have tried detecting the last cell in the table with the modifications, but it turned out to be really buggy. The Add to Cart button would show on random rows.
Edit: Here is the cellForRow method to detect the last row:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... Custom Cell dequeue
// Currently only 3 rows for modifications, so 0-2, last one is 3 for Add to Cart
if(indexPath.row == 3){
cell.textLabel.text = #"Add to Cart";
cell.productName.text = #"";
cell.productDescription.text = #"";
}
else {
...Regular cell items
}
return cell;
}
Are you also returning nil for your viewForFooter method in the other sections?
We will likely need to know how you check if a section has an addToCart button... but here's my guess:
- (CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section {
if (self.isOpen && [self hasCartForSection:section]) {
return 35.0;
}
else {
// One table view style will not allow 0 value for some reason
return 0.00001;
}
}
- (UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section {
if (self.isOpen && [self hasCartForSection:section]) {
UIView *footerView = [UIView.alloc init];
// Build your footer
return footerView;
}
return nil;
}
- (BOOL)hasCartForSection:(int)section {
BOOL someCondition = NO;
// Do your check
if (someCondition) {
return YES;
}
return NO;
}

Show re-order sign for one section while rest sections should not show any controls of a tableView, and enable swipe left delete in edit mode

I am working on an app where I need to reorder rows of section 1. I could achieve the reorder by implementing the tableView delegates. When the table is in editing mode I show reorder for section 1 and no controls for rest sections, but the rows of rest section should be deleted by swipe to left.
I am not sure whether this is possible but my requirement is exact the same.
Work done by me:
Below are the delegates of tableView I implemented:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.myTable isEditing]) {
return UITableViewCellAccessoryNone;
}
return UITableViewCellEditingStyleDelete;
}
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return YES;
}
return NO;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
The above code made the edit mode look as I wanted. Re-order sign got visible for only section 1 & red delete button is also not visible for rest sections (as desired).
Problem:
The rows of sections apart from section 1 were also not being deleted.When I swipe to left nothing happens.
In short in edit mode, section 1 should be re-order enabled and rest sections should work as they work in normal mode i.e swipe left to delete row should be functioning in tableview edit mode.
AFAIK you cannot achieve what you are trying. The two sections are part of the same table which is being edited. So once the table is in editing mode, it will affect all the sections and rows.
what you can do is divide the data in the two sections into two separate tables and load the tables in the header view of each section like this
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0) {
TableViewController1 *tab1 = [[TableViewController1 alloc] initWithStyle:UITableViewStylePlain];
return tab1.tableView;
} else{
TableViewController2 *tab2 = [[TableViewController2 alloc] initWithStyle:UITableViewStylePlain];
return tab2.tableView;
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return self.parentTable.frame.size.height/2;
}
tab1 will have data from first section and similar case for tab2 (forgive the variable naming). The parent table should have grouped style and also scrolling should be disabled for it. This way the two sections can be edited independent of each other. Also, this categorises data and each section becomes independently scrollable. Hope this helps and answers what ur looking for.

Creating Grouped UITableview with Different Cell Types

I need to create a grouped uitableview that includes some sections and possibly different cell types in each sections.
I am trying to create something like old foursquare app, user page (includes 'leaderboard', 'friend suggestions', 'friends', 'stats', 'most explored categories' ... sections).
I am fairly new to ios programming, so that view may not be a grouped uitableview.
What I especially stuck is creating different cells for sections, and finding out which cells are clicked.
My data source will be 2 different NSArray* that consists of different data types, that's why I need different custom cells.
Since you have two different sets of data and you need to display both in different sections, you have to split the data source methods into two.
Basically, choose which dataset you want to be first and off you go.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section)return secondArray.count;
//Essentially, if statements evaluate TRUE and move forward if the inside is 1 or greater (TRUE == 1)
return firstArray.count;
//If the first if statement return hits, then the code will never reach this statement which turns this into a lighter if else statement
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section)
{
//do stuff with second array and choose cell type x
}
else
{
//do stuff with first array and choose cell type y
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get the cell with: UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(indexPath.section)
{
//perform action for second dataset
}
else
{
//perform action for first dataset
}
}
For headers, you can use either of these methods and just keep the same type of styling as above:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
You can create multiple custom subclasses of UITableViewCell, and in the tableView:cellForRowAtIndexPath: method for your UITableViewDataSource, you can use if-statements to determine what type of cell to use.
For example, here's a rough outline of what I might do:
-(UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//First, determine what type of object we're showing
if (indexPath.section == 0) {
//Create and return this cell.
} else if (indexPath.section == 1) {
//Create and return this cell.
}...
}
Here's how you'd implement numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return [firstSectionArray count];
} else if (section == 1) {
return [secondSectionArray count];
} ...
}
For didSelectRowAtIndexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
ObjectSelected *objectSelected = [firstArray objectAtIndex:indexPath.row];
//Now you've got the object, so push a view controller:
DetailViewController *dvc = [[DetailViewController alloc] init];
dvc.objectSelected = objectSelected;
[self.navigationController pushViewController:dvc];
} else if (indexPath.section == 1) {
//Same thing, just call [secondArray objectAtIndex:indexPath.row] instead!
}
}

Resources