Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
186 views
in Technique[技术] by (71.8m points)

ios - ipad: Drag a UITableViewCell from one UITableViewController and drop it into another

my question is, wether or not this is possible, and if so, how would you approach this task?

Does anybody know of an app already using this functionality, or where to get some sample code?

Also, if i'm to implement this on my own without too much knowledge of the topic what would be your estimation on how long it would take to get it done?

One other thing to mention, since it could make things more complicated: The destination table is in editmode per default, so that the user can rearrange the cells (using the standard reordering control in accessory view), which have already been dropped there.

Edit:

I just tried to include a screenshot of a concept image in my post. The image shows one table on the left and a grayish drop area on the right. My customer says that he saw this on other apps, too, so there has to be some kind of ui element that I am not aware of.

I haven't found anything in the developer library about such a drop area, so hopefully one of you can give me directions or clear things up.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Ok, I managed to implement this myself and I'm quite happy with the result. You can drag cells from left (source table) to right (destination table) and also drag cells within the destination table for reodering. If you try to drag a cell from right to left it will be reinserted at the same position where you started dragging (so nothing happens). The destination table also supports deletion of cells, the source table doesn't. So here's the complete code:

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)];
        [gestureRecogniz

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...