I have encountered an issue when trying to reorder rows in UITableView.
I have the function tableView:moveRowAtIndexPath:toIndexPath: triggered, but fromIndexPath is equal to toIndexPath (i.e. source == destination).
I saw the same issue here: uitableview re-order won't work, source always equal to destination
But the solution was - to use different library. That is not a variant for me.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
//fromIndexPath is equal to toIndexPath, so nothing is exchaned
[self.table_data exchangeObjectAtIndex:fromIndexPath.row withObjectAtIndex:toIndexPath.row];
}
My table is in editable mode, I have canMoveRowAtIndexPath: returning YES. My it does not help.
How come? What am I doing wrong?
The problem was in custom pan gesture recognizer.
It somehow was in conflict with rows drag-drop behavior
Setting myGestureRecognizer.cancelsTouchesInView = NO; fixed the issue
Try this. It works.
- (void)viewDidLoad {
[super viewDidLoad];
arr = [NSMutableArray arrayWithObjects:#"First",#"Second",#"Third",#"Fourth", nil];
self.tableView.editing = YES;
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return arr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UILabel *label = (UILabel *)[cell.contentView viewWithTag:100];
[label setText:[arr objectAtIndex:indexPath.row]];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSString *stringToMove = arr[sourceIndexPath.row];
[arr removeObjectAtIndex:sourceIndexPath.row];
[arr insertObject:stringToMove atIndex:destinationIndexPath.row];
}
Check the screenshot -
Related
Hi everyone I am a newbie to iOS.
I have implemented a UITableView with 3 sections in UITableViewController. And I have displayed the section rows to each section.
- (void)viewDidLoad
{
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.navigationItem.rightBarButtonItem = self.editButtonItem;
sectionTittle=[[NSMutableArray alloc]initWithObjects:#"Real Madrid",#"Barcelona",#"Liverpool", nil];
firstSection=[[NSMutableArray alloc]initWithObjects:#"Cr7",#"Garath Bale",#"Pepe",
nil];
secondSection=[[NSMutableArray alloc]initWithObjects:#"Lionel Messi",#"Neymar",#"Pique",
nil];
thirdSection=[[NSMutableArray alloc]initWithObjects:#"Gerrard",#"Saurez",#"Lallana",
nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionTittle.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section==0)
{
return [firstSection count];
}
if(section==1)
{
return [secondSection count];
}
if(section==2)
{
return [thirdSection count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"hi" forIndexPath:indexPath];
cell.textLabel.textColor=[UIColor brownColor];
if (indexPath.section == 0)
{
cell.textLabel.text=[firstSection objectAtIndex:indexPath.row];
}
if (indexPath.section == 1)
{
cell.textLabel.text = [secondSection objectAtIndex:indexPath.row];
}
if (indexPath.section == 2)
{
cell.textLabel.text = [thirdSection objectAtIndex:indexPath.row];
}
// Configure the cell...
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [sectionTittle objectAtIndex:section];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
Now my output looks like this:
I want to move the rows between the these 3 sections. How can I do it..? While I try doing it the row moves between the section, but while saving it creates a problem.
How can i go through it..?
Thanks
You need to utilise UITableView re-ordering capacity. The cells can be re-ordered across sections.
To enable re-ordering mode:
[self.tableView setEditing:TRUE animated:TRUE];
This enables the TableView in editing mode which includes enables deletion mode along with re-ordering. If you do not want the deletion mode implement:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
The re-order support accessory view is shown if you have implemented moveRowAtIndexPath like, for your case:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
// Logic to change data source
NSMutableArray *deleteFrom = [self getDataSourceArrayFromIndexPath:sourceIndexPath];
NSMutableArray *addTo = [self getDataSourceArrayFromIndexPath:destinationIndexPath];
[addTo insertObject:[deleteFrom objectAtIndex:sourceIndexPath.row] atIndex:destinationIndexPath.row];
[deleteFrom removeObjectAtIndex:sourceIndexPath.row];
}
where getDataSourceArrayFromIndexPath is:
-(NSMutableArray*) getDataSourceArrayFromIndexPath:(NSIndexPath*) index
{
switch (index.section) {
case 0:
return self.firstSection;
break;
case 1:
return self.secondSection;
break;
case 2:
return self.thirdSection;
break;
default:
break;
}
return nil;
}
Use This Code
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSMutableArray *arrayTemp=[arrayMain objectAtIndex:sourceIndexPath.row];
[arrayVisibleCountryList removeObjectAtIndex:sourceIndexPath.row];
[arrayVisibleCountryList insertObject:arrayTemp atIndex:destinationIndexPath.row];
}
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
//Uncomment these lines to enable moving a row just within it's current section
if ([sourceIndexPath section] != [proposedDestinationIndexPath section])
{
proposedDestinationIndexPath = sourceIndexPath;
}
return proposedDestinationIndexPath;
}
You can use below tableView method. It moves your cell from sourceIndexPath to destinationIndexPath.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
I am having such an issue right now. I have a UIViewController that has a UITableView, I have it set up so that when the UITableView is in editing mode it returns 3 - circles with the check marks. My UITableView has custom cells with in image and text. When I put the UITableView in edit mode, I am trying to pass an array of the images from multiple selected rows to a second view controller to use those images in a collection view, but I am just having a hard time passing the array of images. Any suggestions would be appreciated.
here is my TableView code:
-(void)didTapEditBUtton:(id)sender{
if ([self.ribbonTableView isEditing]) {
viewButton.hidden = YES;
headerLabel.hidden = NO;
[ribbonTableView setEditing:NO animated:YES];
[selectButton setTitle:#"select"];
}
else {
[selectButton setTitle:#"Cancel"];
// Turn on edit mode
headerLabel.hidden = YES;
viewButton.hidden = NO;
[ribbonTableView setEditing:YES animated:YES];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection (NSInteger)section{
return [ribbonsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
RibbonCustomCell *cell = (RibbonCustomCell *) [ribbonTableView dequeueReusableCellWithIdentifier:#"RibbonDetail"];
if (cell != nil)
{
RibbonsInfo *ribbonsInfo = [ribbonsArray objectAtIndex:indexPath.row];
//NSLog(#"%#", ribbonsInfo);
//Ribbon Image
cell.ribbonImageView.image = ribbonsInfo.ribbonImage;
cell.ribbonLabel.text = ribbonsInfo.ribbonName;
}
return cell;
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return 3;
}
-(void)tableView:(UITableView *)tableView didSelectRowsAtIndexPath:(NSIndexPath *)indexPath{
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
}
You should take the property of NSMutableArray...
#property (nonatomic, strong) NSMutableArray *selectedImages;
- (void)viewDidLoad {
[super viewDidLoad];
self.selectedImages = [NSMutableArray new];
}
now when you select or deselect the cell the delegates are called -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",indexPath);
RibbonsInfo *ribbonsInfo = [ribbonsArray objectAtIndex:indexPath.row];
[self.selectedImages addObject:ribbonsInfo.ribbonImage];
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",indexPath);
if (self.selectedImages.count > 0) {
[self.selectedImages removeObjectAtIndex:indexPath.row];
}
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return 3;
}
Now the selectedImages array contains the selected cell images and you can pass this array.
Hope it will solve your problem.
Utilizing the method of populating a UITableView from this answer, and setting the table to edit mode via:
tableView.editing = true;
And adding these methods:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
}
I am seeing that a user can accidentally(or intentionally) double tab the ordering handle and insert an empty row. This will also kill the scrolling for the table view. Here is an image:
Between "Logs" and "Settings" there is an empty row. I have looped through all rows on the table view via the answers found here, and the empty rows are skipped over as if they don't exist.
I was able to remove the empty rows via [tableView reload] each time a row is moved, which unfortunately results in a kind of jarring snap. However, I haven't been able to re-enabled the scrolling. I am trying to avoid having to make the user close and redisplay the view.
Any one run across this issue and find a suitable work around?
EDIT:
Row deletion is irrelevant - this happens as a result of moving rows around
This is Xcode 6.1 on ios 8/7 - have also seen this Xcode 5.x -> ios 7/8.
We are targeting ipads, so not sure if this is an issue on iphone
Also, better description of how to reproduce:
double tap cell and hold on second tap for a second
drag cell up or down
Posted on Apple forums and submitted bug to Apple. Here was the example project I submitted to them (in which I was able to reproduce said issue):
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableData = [NSMutableArray arrayWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",
#"One",#"Two",#"Three",#"Four",#"Five",
#"One",#"Two",#"Three",#"Four",#"Five",
#"One",#"Two",#"Three",#"Four",#"Five",
#"One",#"Two",#"Three",#"Four",#"Five",
#"One",#"Two",#"Three",#"Four",#"Five", nil];
self.tableView.editing = true;
[self.tableView setTableFooterView:[UIView new]];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.tableView.rowHeight = 20.0;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"ScrollingDisplayCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if( cell == nil )
{
cell = [[[UITableViewCellNoPadding alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease]; // MEMCHK: Autorelease so no ownership implications
cell.textLabel.font = [UIFont fontWithName:#"Courier New" size:17.0];
cell.textLabel.frame = cell.contentView.bounds;
}
// Configure the cell...
cell.textLabel.text = [self.tableData objectAtIndex:indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSString *stringToMove = self.tableData[sourceIndexPath.row];
[self.tableData removeObjectAtIndex:sourceIndexPath.row];
[self.tableData insertObject:stringToMove atIndex:destinationIndexPath.row];
}
And here is UITableViewCellNoPadding : UITableViewCell:
// https://stackoverflow.com/questions/3467288/center-align-text-in-uitableviewcell-problem
-(void)layoutSubviews
{
[super layoutSubviews];
self.textLabel.frame = CGRectMake(0, self.textLabel.frame.origin.y, self.frame.size.width, self.textLabel.frame.size.height);
}
NOTE: It was more difficult to reproduce here than in my own app
Since you specified that users should not be able to delete rows, I added editingStyleForRowAtIndexPath to always return UITableViewCellEditingStyleNone. Without this implementation, UITableViewCellEditingStyleDelete is returned by default.
With the implementation posted below, everything seems to behave well, and I've checked that all edits commit successfully to the table model.
I hope this helps!
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tableModel = [NSMutableArray new];
for (int i = 0; i < 30; i++) {
[self addTableObject];
}
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.editing = true;
}
- (void) addTableObject
{
NSString *rowValue = [NSString stringWithFormat:#"%i", _tableModel.count+1];
[_tableModel addObject:rowValue];
}
#pragma mark - Table view delegate methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [_tableModel objectAtIndex:indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _tableModel.count;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
//Make change in data model
id selectedValue = [_tableModel objectAtIndex:sourceIndexPath.row];
[_tableModel removeObjectAtIndex:sourceIndexPath.row];
[_tableModel insertObject:selectedValue atIndex:destinationIndexPath.row];
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
I am working on a feature like drag and drop cell in tableview for different rows. I am dragging 1st item to last item and scrolling rows to top of the table view. It is working fine up to iOS 7.1 version, but when I tested the same code base with an iOS 8 beta simulator, the drag buttons disappear are I'm not able to drag the cell anymore. Here is my sample code for your reference.
- (void)viewDidLoad
{
[super viewDidLoad];
list = [[NSMutableArray alloc]initWithObjects:#"1", #"2", #"3", #"4", #"5", #"6", #"7", #"8", #"9", #"10", #"11", #"12", #"13", #"14", #"15",#"16", nil];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [list count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"DragCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
cell.showsReorderControl = YES;
}
cell.textLabel.text = [list objectAtIndex:indexPath.row];
return cell;
}
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
- (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSInteger sourceRow = sourceIndexPath.row;
NSInteger destRow = destinationIndexPath.row;
id object = [list objectAtIndex:sourceRow];
[list removeObjectAtIndex:sourceRow];
[list insertObject:object atIndex:destRow];
}
Please let me know if you guys have the same issue in iOS 8.
I can confirm that. I have a Tableview with Cells wich can be sorted manually. On iOS8b2 there are no reorder Buttons!
i found out that the reorder controls won't appear if don't have
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
implemented, even if you don't do anything here!!
I use custom cell.I want to move this cell (change position of the cells)
i used this delegations
UITableViewDataSource,UITableViewDelegate
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *Cellidentifier = #"Celledit";
CellEdit *editCell =[tableView dequeueReusableCellWithIdentifier:Cellidentifier];
if (!editCell) {
editCell = [[CellEdit alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Cellidentifier];
}
MItem *mItem = [mItems objectAtIndex:[indexPath row]];
---------------------------------
// set data 3 labales in the cell
---------------------------------
editCell.editdelegate = self;
return editCell;
editcell is my custom cell
[_tableViewEdit setEditing:YES animated:YES]; this line put in - (void)viewDidLoad
i want to edit it always
// table view change cells
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
- (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSInteger sourceRow = sourceIndexPath.row;
NSInteger destRow = destinationIndexPath.row;
id object = [minutesItems objectAtIndex:sourceRow];
[minutesItems removeObjectAtIndex:sourceRow];
[minutesItems insertObject:object atIndex:destRow];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
for (UIControl *control in cell.subviews)
{
if ([control isMemberOfClass:NSClassFromString(#"UITableViewCellReorderControl")] && [control.subviews count] > 0)
{
for (UIControl *someObj in control.subviews)
{
if ([someObj isMemberOfClass:[UIImageView class]])
{
UIImage *img = [UIImage imageNamed:#"logocoffee.png"];
((UIImageView*)someObj).frame = CGRectMake(0.0, 0.0, 43.0, 43.0);
((UIImageView*)someObj).image = img;
}
}
}
}
}
}
to move the cell simulator not showing right side control icon
why this?
that means cant move costume cells?
Try this code,
You should use below two method,
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
Use this method for moving the row
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
[label1array exchangeObjectAtIndex:fromIndexPath.row withObjectAtIndex:toIndexPath.row];
[label2array exchangeObjectAtIndex:fromIndexPath.row withObjectAtIndex:toIndexPath.row];
[label3array exchangeObjectAtIndex:fromIndexPath.row withObjectAtIndex:toIndexPath.row];
}
Custom cells can be moved as well.
From your code samples we don't see where you are setting your tableview in the editing mode.
Perhaps the issue is because you are never setting the editing mode.
If so, try to add an Edit button in the title bar for example, which should be linked to a method such as:
- (IBAction) EditTable:(id)sender{
if(self.editing)
{
[super setEditing:NO animated:NO];
[yourTableView setEditing:NO animated:NO];
[yourTableView reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Edit"];
}
else
{
[super setEditing:YES animated:YES];
[yourTableView setEditing:YES animated:YES];
[yourTableView reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Done"];
}
}
I think this one should resolve your issue.
Edit: To resume in your case, as a minimum, you only need to set your table view in the editing mode in viewDidLoad, and to update it if needed:
[yourTableView setEditing:YES animated:YES];
[yourTableView reloadData];
and to implement both callbacks:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
//Even if the method is empty you should be seeing both rearrangement icon and animation.
}
I tried with custom cells and it's working fine.