ipad:从一个 UITableViewController 拖动一个 UITableViewCell 并将其放入另一个 [英] ipad: Drag a UITableViewCell from one UITableViewController and drop it into another

查看:23
本文介绍了ipad:从一个 UITableViewController 拖动一个 UITableViewCell 并将其放入另一个的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是,这是否可行,如果可行,您将如何处理这项任务?

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.

我只是尝试在我的帖子中包含一个概念图片的屏幕截图.图像显示左侧的一个表格和右侧的灰色拖放区域.我的客户说他也在其他应用上看到过这个,所以肯定有某种我不知道的 ui 元素.

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.

推荐答案

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

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

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

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

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

Here is an example of how to use it:

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 并继续将其用于您想做的任何事情.

Then, after you are done editing you just read dropTable.dstData and continue using it for what ever you want to do.

UIDropTableViewController.m 中,您可能需要根据自己的需要调整 initDraggedCellWithCellsrcTableCellForRowAtIndexPathdstTableCellForRowAtIndexPath就单元格表示而言.

In UIDropTableViewController.m you might want to adjust initDraggedCellWithCell, srcTableCellForRowAtIndexPath and dstTableCellForRowAtIndexPath for your own needs as far as cell representation goes.

这篇关于ipad:从一个 UITableViewController 拖动一个 UITableViewCell 并将其放入另一个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆