【发布时间】:2015-05-07 10:13:05
【问题描述】:
继续我之前的问题 moveRowAtIndexPath - Moving cells between sections
我已经能够使用传统的moveRowAtIndexPath 在部分之间移动单元格,即:将标记从销售移动到营销。
但是现在我想更进一步,在表格视图上添加长按手势,并允许我移动单元格,而不是简单地在单元格上使用长按。
作为参考,我的表格是Employees 的列表,他们在不同的Departments 工作;其中模型是自定义的,但只包含简单的名称字符串。
我的行设置是这样的;
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [_objects count];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
Department *department = [_objects objectAtIndex:section];
return [department.employees count];
}
我当前的 moveRowAtIndexPath 是:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
if (fromIndexPath != toIndexPath ) {
Department *departmentFrom = [_objects objectAtIndex:fromIndexPath.section];
Department *departmentTo = [_objects objectAtIndex:toIndexPath.section];
Employee *employee = [departmentFrom.employees objectAtIndex:fromIndexPath.row];
[departmentFrom.employees removeObjectAtIndex:fromIndexPath.row];
[departmentTo.employees insertObject:employee atIndex:toIndexPath.row];
[tableView reloadData];
}
}
所以现在我在 viewDidLoad 期间将 longpress 添加到表格中,ala;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)];
[self.tableView addGestureRecognizer:longPress];
然后终于有了我的长按代码本身;
- (IBAction)longPressGestureRecognized:(id)sender {
UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
UIGestureRecognizerState state = longPress.state;
CGPoint location = [longPress locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
static UIView *snapshot = nil; ///< A snapshot of the row user is moving.
static NSIndexPath *sourceIndexPath = nil; ///< Initial index path, where gesture begins.
switch (state) {
case UIGestureRecognizerStateBegan: {
if (indexPath) {
sourceIndexPath = indexPath;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
// Take a snapshot of the selected row using helper method.
snapshot = [self customSnapshoFromView:cell];
// Add the snapshot as subview, centered at cell's center...
__block CGPoint center = cell.center;
snapshot.center = center;
snapshot.alpha = 0.0;
[self.tableView addSubview:snapshot];
[UIView animateWithDuration:0.25 animations:^{
// Offset for gesture location.
center.y = location.y;
snapshot.center = center;
snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
snapshot.alpha = 0.98;
cell.alpha = 0.0;
} completion:^(BOOL finished) {
cell.hidden = YES;
}];
}
break;
}
case UIGestureRecognizerStateChanged: {
CGPoint center = snapshot.center;
center.y = location.y;
snapshot.center = center;
// Is destination valid and is it different from source?
if (indexPath && ![indexPath isEqual:sourceIndexPath]) {
// ... update data source.
// ... move the rows.
[self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
// ... and update source so it is in sync with UI changes.
sourceIndexPath = indexPath;
}
break;
}
default: {
// Clean up.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
cell.hidden = NO;
cell.alpha = 0.0;
[UIView animateWithDuration:0.25 animations:^{
snapshot.center = cell.center;
snapshot.transform = CGAffineTransformIdentity;
snapshot.alpha = 0.0;
cell.alpha = 1.0;
} completion:^(BOOL finished) {
sourceIndexPath = nil;
[snapshot removeFromSuperview];
snapshot = nil;
}];
break;
}
}
}
#pragma mark - Helper methods
/** @brief Returns a customized snapshot of a given view. */
- (UIView *)customSnapshoFromView:(UIView *)inputView {
// Make an image from the input view.
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, NO, 0);
[inputView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Create an image view.
UIView *snapshot = [[UIImageView alloc] initWithImage:image];
snapshot.layer.masksToBounds = NO;
snapshot.layer.cornerRadius = 0.0;
snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0);
snapshot.layer.shadowRadius = 5.0;
snapshot.layer.shadowOpacity = 0.4;
return snapshot;
}
可悲的是,这在UIGestureRecognizerStateChanged 中崩溃了,它试图移动单元格;它与移动前后数组的不一致有关。
另外,我不确定我是否做得对;这种模式是否适用于基于部分的部门和员工列表?
无论如何,我的查询是:如何将长按手势添加到由部分组成的 tableview 单元格,或者..我想使用长按将 Tom 从 Sales 移至 Marketing。
鉴于上面的代码,这可能吗?
编辑;
我得到的崩溃是:
'NSInternalInconsistencyException',原因:'无效更新:无效 第 0 节中的行数。包含在第 0 节中的行数 更新后的现有节(3)必须等于 更新之前该部分中包含的行 (3),加号或减号 从该部分插入或删除的行数(0 插入, 0 已删除)加或减移入或移出的行数 该部分(0 移入,1 移出)。 *** 首先 throw 调用 st
进一步更新:@14-Jan-2016
事实证明,接受的答案仍然导致我崩溃。原因是它假设正在发生交换。如果不是这种情况。
我通过重复我的代码来删除一个项目然后重新添加它来解决问题。
这贴在下面;
case UIGestureRecognizerStateChanged: {
CGPoint center = snapshot.center;
center.y = location.y;
center.x = location.x;
snapshot.center = center;
// Is destination valid and is it different from source?
if (indexPath && ![indexPath isEqual:sourceIndexPath])
{
Department *departmentFrom = [_objects objectAtIndex:sourceIndexPath.section];
Department *departmentTo = [_objects objectAtIndex:indexPath.section];
[self.tableView beginUpdates];
Employee *employee = [departmentFrom.employees objectAtIndex:sourceIndexPath.row];
[departmentFrom.employees removeObjectAtIndex:sourceIndexPath.row];
[departmentTo.employees insertObject:employee atIndex:indexPath.row];
[self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
[self.tableView endUpdates];
// ... and update source so it is in sync with UI changes.
sourceIndexPath = indexPath;
}
break;
}
我能看到的唯一问题是 tableView:moveRowAtIndexPath 和这段代码都在重复相同的代码。
但我可以稍后清理。
谢谢
【问题讨论】:
标签: objective-c uitableview uigesturerecognizer long-press