2011-06-28 6 views
15

mi pregunta es, aunque no sean de esto es posible, y si es así, ¿cómo abordar esta tarea?iPad: Arrastre un UITableViewCell de un UITableViewController y colocarlo en otra

¿Alguien sabe de una aplicación que ya utilizan esta funcionalidad, o dónde obtener un código de ejemplo?

Además, si voy a poner en práctica esto por mi cuenta sin demasiado conocimiento del tema lo que sería su estimación de cuánto tiempo se tardaría en lograr que se haga?

Otra cosa que mencionar, ya que podría complicar las cosas: la tabla de destino está en modo de edición por defecto, para que el usuario pueda reorganizar las celdas (usando el control de reordenamiento estándar en la vista de accesorios), que ya han sido tirado allí.

Editar:

que sólo trató de incluir una captura de pantalla de una imagen de concepto de en mi post. La imagen muestra una tabla a la izquierda y una zona gris a la derecha. Mi cliente dice que también vio esto en otras aplicaciones, por lo que tiene que haber algún tipo de elemento de interfaz de usuario del que no tenga conocimiento.

no he encontrado nada en la biblioteca de desarrollo sobre un área tan caída, así que espero que uno de ustedes me puede dar instrucciones o aclarar las cosas.

+0

mira esto: https://github.com/Ice3SteveFortune/i3-dragndrop – sf13579

Respuesta

36

Ok, me las arreglé para poner en práctica esto mismo y estoy bastante contento con el resultado. Puede arrastrar celdas desde la izquierda (tabla de origen) a la derecha (tabla de destino) y también arrastrar celdas dentro de la tabla de destino para volver a ordenar. Si intenta arrastrar una celda de derecha a izquierda, se reinserta en la misma posición donde comenzó a arrastrar (para que no ocurra nada). La tabla de destino también admite la eliminación de celdas, la tabla fuente no. Así que aquí está el código completo:

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 

Aquí es un ejemplo de cómo usarlo:

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]; 

Entonces, después de Ya terminaste de editar, solo lees dropTable.dstData y sigues usándolo para la noche lo que quieres hacer

En UIDropTableViewController.m es posible que desee ajustar initDraggedCellWithCell, srcTableCellForRowAtIndexPath y dstTableCellForRowAtIndexPath para sus propias necesidades en cuanto a la representación celular va.

+1

bueno muchas gracias funciona código de casa. – Dhara

+0

Utilicé el código anterior como base de lo que necesitaba. muy eficientemente escrito. Gracias – Jatin

+0

El código anterior funciona bastante bien – Jingwei

4

También tuve que resolver un problema similar, también. Aquí hay un enlace a un ejemplo de compilación y ejecución en github.

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

Enjoy.

1

Sé que esto es una pregunta muy antigua pero tengo recientemente implementado el código christoph gave in his answer en una vista sencilla clase de ayuda - pensó que podría ser útil:

i3-dragndrop

es compatible tanto con UITableViews y UICollectionViews como fuente y destinos.

ACTUALIZACIÓN

Me acabo de dar cuenta de la versión 2 de la biblioteca mencionada: BetweenKit. Se basa en los conceptos originales pero admite una amplia gama de características nuevas, como múltiples colecciones de objetivos, renderizado personalizado y mucho más. Espero eso ayude !

Cuestiones relacionadas