ipad:从一个UITableViewController中拖出一个UITableViewCell,并将其放入另一个UITableViewController中

我的问题是,这是否可能,如果是的话,你将如何处理这个任务?

有人知道一个应用程序已经使用这个function,或者在哪里得到一些示例代码?

另外,如果我自己实现这一点,不需要对这个主题有太多的了解,那么对于完成这个任务需要多长时间,你会做出什么估计?

还有一件事要说,因为它可能使事情变得更加复杂:目标表是默认情况下处于editmode状态,这样用户可以重新排列已经在那里丢弃的单元格(使用附件视图中的标准重新sorting控件)。

编辑:

我只是试图在我的文章中包含一个概念图片的截图。 图像左侧显示一张桌面,右侧显示灰色的下落区域。 我的客户说他也在其他应用程序上看到过,所以必须有某种我不知道的UI元素。

我还没有在开发者库中find任何关于这样的放置区域的信息,所以希望你们中的一个能够给我指示或者清理一下。

好吧,我自己实现了这一点,我对结果很满意。 您可以将单元格从左侧(源表格)拖动到右侧(目标表格),也可以拖动目标表格中的单元格进行重新编码。 如果您尝试从右向左拖动一个单元格,它将被重新插入到您开始拖动的位置(因此没有任何反应)。 目标表还支持删除单元格,源表格则不支持。 所以这是完整的代码:

UIDropTableViewController.h

#import <UIKit/UIKit.h> @interface UIDropTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate> { UINavigationItem* srcTableNavItem; UINavigationItem* dstTableNavItem; UITableView* srcTableView; UITableView* dstTableView; UITableViewCell* draggedCell; UIView* dropArea; NSMutableArray* srcData; NSMutableArray* dstData; id draggedData; BOOL dragFromSource; // used for reodering NSIndexPath* pathFromDstTable; // used to reinsert data when reodering fails } @property (nonatomic, readonly) NSArray* srcData; @property (nonatomic, readonly) NSArray* dstData; - (id)initWithFrame:(CGRect)frame SourceData:(NSArray*)sourceData DestinationData:(NSArray*)destinationData; - (void)setSrcTableTitle:(NSString*)title; - (void)setDstTableTitle:(NSString*)title; @end 

UIDropTableViewController.m

 #import "UIDropTableViewController.h" #define kCellIdentifier @"DropTableCell" #define kCellHeight 44 #define kNavBarHeight 30 // forward declaration of private helper methods @interface UIDropTableViewController() - (void)setupSourceTableWithFrame:(CGRect)frame; - (void)setupDestinationTableWithFrame:(CGRect)frame; - (void)initDraggedCellWithCell:(UITableViewCell*)cell AtPoint:(CGPoint)point; - (void)startDragging:(UIPanGestureRecognizer *)gestureRecognizer; - (void)startDraggingFromSrcAtPoint:(CGPoint)point; - (void)startDraggingFromDstAtPoint:(CGPoint)point; - (void)doDrag:(UIPanGestureRecognizer *)gestureRecognizer; - (void)stopDragging:(UIPanGestureRecognizer *)gestureRecognizer; - (UITableViewCell*)srcTableCellForRowAtIndexPath:(NSIndexPath*)indexPath; - (UITableViewCell*)dstTableCellForRowAtIndexPath:(NSIndexPath*)indexPath; @end @implementation UIDropTableViewController @synthesize srcData, dstData; #pragma mark - #pragma mark Public Methods - (void)setSrcTableTitle:(NSString*)title { srcTableNavItem.title = title; } - (void)setDstTableTitle:(NSString*)title { dstTableNavItem.title = title; } #pragma mark - #pragma mark UIViewController - (id)initWithFrame:(CGRect)frame SourceData:(NSArray*)sourceData DestinationData:(NSArray*)destinationData { self = [super init]; if (self) { self.view.clipsToBounds = YES; self.view.frame = frame; int width = frame.size.width; int height = frame.size.height; // set up data srcData = [[NSMutableArray alloc] initWithArray:sourceData]; dstData = [[NSMutableArray alloc] initWithArray:destinationData]; draggedCell = nil; draggedData = nil; pathFromDstTable = nil; // set up views [self setupSourceTableWithFrame:CGRectMake(0, 0, width / 2, height)]; [self setupDestinationTableWithFrame:CGRectMake(width / 2, 0, width / 2, height)]; UIView* separator = [[UIView alloc] initWithFrame:CGRectMake(width / 2, 0, 1, height)]; separator.backgroundColor = [UIColor blackColor]; [self.view addSubview:separator]; [separator release]; // set up gestures UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanning:)]; [self.view addGestureRecognizer:panGesture]; [panGesture release]; } return self; } - (void)dealloc { [srcTableNavItem release]; [dstTableNavItem release]; [srcTableView release]; [dstTableView release]; [dropArea release]; [srcData release]; [dstData release]; if(draggedCell != nil) [draggedCell release]; if(draggedData != nil) [draggedData release]; if(pathFromDstTable != nil) [pathFromDstTable release]; [super dealloc]; } - (void)viewWillAppear:(BOOL)animated { [srcTableView reloadData]; [dstTableView reloadData]; [UIView animateWithDuration:0.2 animations:^ { CGRect frame = dstTableView.frame; frame.size.height = kCellHeight * [dstData count]; dstTableView.frame = frame; }]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return UIInterfaceOrientationIsLandscape(interfaceOrientation); } #pragma mark - #pragma mark Helper methods for initialization - (void)setupSourceTableWithFrame:(CGRect)frame { srcTableNavItem = [[UINavigationItem alloc] init]; srcTableNavItem.title = @"Source Table"; CGRect navBarFrame = frame; navBarFrame.size.height = kNavBarHeight; UINavigationBar* navigationBar = [[UINavigationBar alloc] initWithFrame:navBarFrame]; [navigationBar pushNavigationItem:srcTableNavItem animated:false]; [navigationBar setTintColor:[UIColor lightGrayColor]]; [self.view addSubview:navigationBar]; [navigationBar release]; CGRect tableFrame = frame; tableFrame.origin.y = kNavBarHeight; tableFrame.size.height -= kNavBarHeight; srcTableView = [[UITableView alloc] initWithFrame:tableFrame]; [srcTableView setDelegate:self]; [srcTableView setDataSource:self]; [self.view addSubview:srcTableView]; } - (void)setupDestinationTableWithFrame:(CGRect)frame { dstTableNavItem = [[UINavigationItem alloc] init]; dstTableNavItem.title = @"Destination Table"; CGRect navBarFrame = frame; navBarFrame.size.height = kNavBarHeight; UINavigationBar* navigationBar = [[UINavigationBar alloc] initWithFrame:navBarFrame]; [navigationBar pushNavigationItem:dstTableNavItem animated:false]; [navigationBar setTintColor:[UIColor lightGrayColor]]; [self.view addSubview:navigationBar]; [navigationBar release]; CGRect dropAreaFrame = frame; dropAreaFrame.origin.y = kNavBarHeight; dropAreaFrame.size.height -= kNavBarHeight; dropArea = [[UIView alloc] initWithFrame:dropAreaFrame]; [dropArea setBackgroundColor:[UIColor grayColor]]; [self.view addSubview:dropArea]; CGRect contentFrame = dropAreaFrame; contentFrame.origin = CGPointMake(0, 0); UILabel* dropAreaLabel = [[UILabel alloc] initWithFrame:contentFrame]; dropAreaLabel.backgroundColor = [UIColor clearColor]; dropAreaLabel.font = [UIFont boldSystemFontOfSize:12]; dropAreaLabel.textAlignment = UITextAlignmentCenter; dropAreaLabel.textColor = [UIColor whiteColor]; dropAreaLabel.text = @"Drop items here..."; [dropArea addSubview:dropAreaLabel]; [dropAreaLabel release]; CGRect tableFrame = contentFrame; tableFrame.size.height = kCellHeight * [dstData count]; dstTableView = [[UITableView alloc] initWithFrame:tableFrame]; [dstTableView setEditing:YES]; [dstTableView setDelegate:self]; [dstTableView setDataSource:self]; [dropArea addSubview:dstTableView]; } - (void)initDraggedCellWithCell:(UITableViewCell*)cell AtPoint:(CGPoint)point { // get rid of old cell, if it wasn't disposed already if(draggedCell != nil) { [draggedCell removeFromSuperview]; [draggedCell release]; draggedCell = nil; } CGRect frame = CGRectMake(point.x, point.y, cell.frame.size.width, cell.frame.size.height); draggedCell = [[UITableViewCell alloc] init]; draggedCell.selectionStyle = UITableViewCellSelectionStyleGray; draggedCell.textLabel.text = cell.textLabel.text; draggedCell.textLabel.textColor = cell.textLabel.textColor; draggedCell.highlighted = YES; draggedCell.frame = frame; draggedCell.alpha = 0.8; [self.view addSubview:draggedCell]; } #pragma mark - #pragma mark UIGestureRecognizer - (void)handlePanning:(UIPanGestureRecognizer *)gestureRecognizer { switch ([gestureRecognizer state]) { case UIGestureRecognizerStateBegan: [self startDragging:gestureRecognizer]; break; case UIGestureRecognizerStateChanged: [self doDrag:gestureRecognizer]; break; case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: case UIGestureRecognizerStateFailed: [self stopDragging:gestureRecognizer]; break; default: break; } } #pragma mark - #pragma mark Helper methods for dragging - (void)startDragging:(UIPanGestureRecognizer *)gestureRecognizer { CGPoint pointInSrc = [gestureRecognizer locationInView:srcTableView]; CGPoint pointInDst = [gestureRecognizer locationInView:dstTableView]; if([srcTableView pointInside:pointInSrc withEvent:nil]) { [self startDraggingFromSrcAtPoint:pointInSrc]; dragFromSource = YES; } else if([dstTableView pointInside:pointInDst withEvent:nil]) { [self startDraggingFromDstAtPoint:pointInDst]; dragFromSource = NO; } } - (void)startDraggingFromSrcAtPoint:(CGPoint)point { NSIndexPath* indexPath = [srcTableView indexPathForRowAtPoint:point]; UITableViewCell* cell = [srcTableView cellForRowAtIndexPath:indexPath]; if(cell != nil) { CGPoint origin = cell.frame.origin; origin.x += srcTableView.frame.origin.x; origin.y += srcTableView.frame.origin.y; [self initDraggedCellWithCell:cell AtPoint:origin]; cell.highlighted = NO; if(draggedData != nil) { [draggedData release]; draggedData = nil; } draggedData = [[srcData objectAtIndex:indexPath.row] retain]; } } - (void)startDraggingFromDstAtPoint:(CGPoint)point { NSIndexPath* indexPath = [dstTableView indexPathForRowAtPoint:point]; UITableViewCell* cell = [dstTableView cellForRowAtIndexPath:indexPath]; if(cell != nil) { CGPoint origin = cell.frame.origin; origin.x += dropArea.frame.origin.x; origin.y += dropArea.frame.origin.y; [self initDraggedCellWithCell:cell AtPoint:origin]; cell.highlighted = NO; if(draggedData != nil) { [draggedData release]; draggedData = nil; } draggedData = [[dstData objectAtIndex:indexPath.row] retain]; // remove old cell [dstData removeObjectAtIndex:indexPath.row]; [dstTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationMiddle]; pathFromDstTable = [indexPath retain]; [UIView animateWithDuration:0.2 animations:^ { CGRect frame = dstTableView.frame; frame.size.height = kCellHeight * [dstData count]; dstTableView.frame = frame; }]; } } - (void)doDrag:(UIPanGestureRecognizer *)gestureRecognizer { if(draggedCell != nil && draggedData != nil) { CGPoint translation = [gestureRecognizer translationInView:[draggedCell superview]]; [draggedCell setCenter:CGPointMake([draggedCell center].x + translation.x, [draggedCell center].y + translation.y)]; [gestureRecognizer setTranslation:CGPointZero inView:[draggedCell superview]]; } } - (void)stopDragging:(UIPanGestureRecognizer *)gestureRecognizer { if(draggedCell != nil && draggedData != nil) { if([gestureRecognizer state] == UIGestureRecognizerStateEnded && [dropArea pointInside:[gestureRecognizer locationInView:dropArea] withEvent:nil]) { NSIndexPath* indexPath = [dstTableView indexPathForRowAtPoint:[gestureRecognizer locationInView:dstTableView]]; if(indexPath != nil) { [dstData insertObject:draggedData atIndex:indexPath.row]; [dstTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationMiddle]; } else { [dstData addObject:draggedData]; [dstTableView reloadData]; } } else if(!dragFromSource && pathFromDstTable != nil) { // insert cell back where it came from [dstData insertObject:draggedData atIndex:pathFromDstTable.row]; [dstTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:pathFromDstTable] withRowAnimation:UITableViewRowAnimationMiddle]; [pathFromDstTable release]; pathFromDstTable = nil; } [UIView animateWithDuration:0.3 animations:^ { CGRect frame = dstTableView.frame; frame.size.height = kCellHeight * [dstData count]; dstTableView.frame = frame; }]; [draggedCell removeFromSuperview]; [draggedCell release]; draggedCell = nil; [draggedData release]; draggedData = nil; } } #pragma mark - #pragma mark UITableViewDataSource - (BOOL)tableView:(UITableView*)tableView canMoveRowAtIndexPath:(NSIndexPath*)indexPath { // disable build in reodering functionality return NO; } - (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // enable cell deletion for destination table if([tableView isEqual:dstTableView] && editingStyle == UITableViewCellEditingStyleDelete) { [dstData removeObjectAtIndex:indexPath.row]; [dstTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [UIView animateWithDuration:0.2 animations:^ { CGRect frame = dstTableView.frame; frame.size.height = kCellHeight * [dstData count]; dstTableView.frame = frame; }]; } } - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { // tell our tables how many rows they will have int count = 0; if([tableView isEqual:srcTableView]) { count = [srcData count]; } else if([tableView isEqual:dstTableView]) { count = [dstData count]; } return count; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return kCellHeight; } - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { UITableViewCell* result = nil; if([tableView isEqual:srcTableView]) { result = [self srcTableCellForRowAtIndexPath:indexPath]; } else if([tableView isEqual:dstTableView]) { result = [self dstTableCellForRowAtIndexPath:indexPath]; } return result; } #pragma mark - #pragma mark Helper methods for table stuff - (UITableViewCell*)srcTableCellForRowAtIndexPath:(NSIndexPath*)indexPath { // tell our source table what kind of cell to use and its title for the given row UITableViewCell *cell = [srcTableView dequeueReusableCellWithIdentifier:kCellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.textLabel.textColor = [UIColor darkGrayColor]; } cell.textLabel.text = [[srcData objectAtIndex:indexPath.row] description]; return cell; } - (UITableViewCell*)dstTableCellForRowAtIndexPath:(NSIndexPath*)indexPath { // tell our destination table what kind of cell to use and its title for the given row UITableViewCell *cell = [dstTableView dequeueReusableCellWithIdentifier:kCellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.textLabel.textColor = [UIColor darkGrayColor]; } cell.textLabel.text = [[dstData objectAtIndex:indexPath.row] description]; return cell; } @end 

这是一个如何使用它的例子:

 NSArray* srcData = [NSArray arrayWithObjects:@"item0", @"item1", @"item2", @"item3", @"item4", nil]; NSArray* dstData = [NSArray arrayWithObjects:@"item5", @"item6", nil]; dropTable = [[UIDropTableViewController alloc] initWithFrame:CGRectMake(100, 100, 600, 500) SourceData:srcData DestinationData:dstData]; [dropTable setSrcTableTitle:@"Bla"]; [dropTable setDstTableTitle:@"Blub"]; [[dropTable.view layer] setBorderColor:[[UIColor darkGrayColor] CGColor]]; [[dropTable.view layer] setBorderWidth:1]; [[dropTable.view layer] setCornerRadius:2]; [self.view addSubview:dropTable.view]; 

然后,在完成编辑之后,您只需阅读dropTable.dstData并继续使用它即可进行任何您想要的操作。

UIDropTableViewController.m您可能需要根据自己的需要调整initDraggedCellWithCellsrcTableCellForRowAtIndexPathdstTableCellForRowAtIndexPath ,直到单元格表示变为止。

我也必须解决类似的问题。 这是一个链接到github上编译和运行的例子。

 https://github.com/luminixinc/UITableViewDragAndDropExample.git 

请享用。

我知道这是一个非常古老的问题,但我最近实现了代码christoph在一个简单的视图助手类中给出的答案 – 认为这可能是有用的:

I3-dragndrop

它支持UITableViewsUICollectionViews作为源和目的地。

UPDATE

我刚刚意识到上述库的版本2: BetweenKit 。 它build立在原始概念的基础上,但支持多种新function,如多个目标集合,自定义渲染等等。 希望能帮助到你 !

你可能已经知道了这个和/或遗忘了,但这是谁想知道如何做到这一点,并遇到这个stackoverflow页面。

没有故事板和没有ARC的例子: https : //github.com/josh2112/iPad-UITableView-DnD-Demo

以故事板和ARC为例: https : //github.com/erikthiem/TestDragAndDropStoryboardARC

上面的christoph代码和Tom K的全function示例项目对我来说都是说明性的。

Tom K的一个小例子,运行示例如下: https : //github.com/luminixinc/UITableViewDragAndDropExample.git IBOutlet在从故事板实例化的“UserDetailViewController”中断。

此故事板的解决方法instantiateViewControllerWithIdentifier不设置IBOutlets