IOS - Разрешить перемещение строки по умолчанию в `UITableView` без режима редактирования
Я хочу разрешить перемещение строк по умолчанию в UITableView
, не находясь в режиме редактирования, и без ущерба для поведения по умолчанию UITableView
.
![movable cell]()
На изображении выше отображается ячейка в режиме редактирования с включенным движением.
Я попробовал просто запустить for (UIView *subview in cell.subviews)
(пока мой UITableView
находился в режиме редактирования), но кнопка не включалась:
<UITableViewCellScrollView: 0x8cabd80; frame = (0 0; 320 44); autoresize = W+H; gestureRecognizers = <NSArray: 0x8c9ba20>; layer = <CALayer: 0x8ca14b0>; contentOffset: {0, 0}>
Как разрешить/добавить движение "button" без включения режима редактирования в моем UITableView
?
Создание и добавление UIButton
с по умолчанию function
для перемещения также является опцией.
Ответы
Ответ 1
Я действительно делаю что-то подобное для одного из моих приложений. Он использует методы делегата для редактирования таблицы и немного "обманывает" пользователя. 100% встроенных функциональных возможностей Apple.
1 - Задайте таблицу для редактирования (я делаю это в viewWillAppear)
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.tableView setEditing:YES];
}
2 - Скрыть значок аксессуара по умолчанию:
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
//remove any editing accessories (AKA) delete button
return UITableViewCellAccessoryNone;
}
3 - Держите режим редактирования от перемещения всего вправо (в ячейке)
-(BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
4 - На этом этапе вы сможете перетаскивать ячейки, не выглядя так, как будто они находятся в режиме редактирования. Здесь мы обманываем пользователя. Создайте свой собственный значок "move" (три строки в случае по умолчанию, любой значок, который вы хотите в своем случае) и добавьте изображение вправо, где он обычно будет проходить по ячейке.
5 - Наконец, реализуем метод делегата, чтобы фактически изменить ваш базовый источник данных.
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
//Get original id
NSMutableArray *originalArray = [self.model.items objectAtIndex:sourceIndexPath.section];
Item * original = [originalArray objectAtIndex:sourceIndexPath.row];
//Get destination id
NSMutableArray *destinationArray = [self.model.items objectAtIndex:destinationIndexPath.section];
Item * destination = [destinationArray objectAtIndex:destinationIndexPath.row];
CGPoint temp = CGPointMake([original.section intValue], [original.row intValue]);
original.row = destination.row;
original.section = destination.section;
destination.section = @(temp.x);
destination.row = @(temp.y);
//Put destination value in original array
[originalArray replaceObjectAtIndex:sourceIndexPath.row withObject:destination];
//put original value in destination array
[destinationArray replaceObjectAtIndex:destinationIndexPath.row withObject:original];
//reload tableview smoothly to reflect changes
dispatch_async(dispatch_get_main_queue(), ^{
[UIView transitionWithView:tableView duration:duration options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[tableView reloadData];
} completion:NULL];
});
}
Ответ 2
Ответ Уильяма Фалькона в быстро
1 - Задайте таблицу для редактирования (я делаю это в viewWillAppear)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated: animated)
tableView.setEditing(true, animated: false)
}
2 - Скрыть значок аксессуара по умолчанию:
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
3 - Держите режим редактирования от перемещения всего вправо (в ячейке)
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
4 - Не требуется в быстрой 3
5 - Изменить порядок массива
Дополнительная заметка
Если вы хотите, чтобы ячейки вашей таблицы были выбраны, добавьте следующий код в функцию viewWillAppear()
.
tableView.allowsSelectionDuringEditing = true
Ответ 3
Если вы не хотите устанавливать UITableView
в режим редактирования, вам нужно будет переосмыслить возможность перетаскивания ячеек.
Я представляю довольно полное решение, которое позволяет пользователю перемещать строки вокруг видимой области UITableView
. Он работает, находится ли режим UITableView
в режиме редактирования или нет. Вам нужно будет расширить его, если вы хотите, чтобы таблица прокручивалась, когда строка перетаскивается вверху или внизу видимой области. Вероятно, некоторые неудачные и крайние случаи вам понадобятся для поиска.
@implementation TSTableViewController
{
NSMutableArray* _dataSource;
}
- (void) viewDidLoad
{
[super viewDidLoad];
_dataSource = [NSMutableArray new];
for ( int i = 0 ; i < 10 ; i++ )
{
[_dataSource addObject: [NSString stringWithFormat: @"cell %d", i]];
}
}
- (void) longPress: (UILongPressGestureRecognizer*) lpgr
{
static NSString* dragCellData = nil;
static UIView* dragCellView = nil;
static NSInteger dragCellOffset = 0;
// determine the cell we're hovering over, etc:
CGPoint pt = [lpgr locationInView: self.tableView];
NSIndexPath* ip = [self.tableView indexPathForRowAtPoint: pt];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath: ip];
CGPoint ptInCell = [lpgr locationInView: cell];
// where the current placeholder cell is, if any:
NSInteger placeholderIndex = [_dataSource indexOfObject: @"placeholder"];
switch ( lpgr.state )
{
case UIGestureRecognizerStateBegan:
{
// get a snapshot-view of the cell we're going to drag:
cell.selected = cell.highlighted = NO;
dragCellView = [cell snapshotViewAfterScreenUpdates: YES];
dragCellView.clipsToBounds = NO;
dragCellView.layer.shadowRadius = 10;
dragCellView.layer.shadowColor = [UIColor blackColor].CGColor;
dragCellView.layer.masksToBounds = NO;
dragCellView.frame = [cell convertRect: cell.bounds
toView: self.tableView.window];
// used to position the dragCellView nicely:
dragCellOffset = ptInCell.y;
// the cell will be removed from the view hierarchy by the tableview, so transfer the gesture recognizer to our drag view, and add it into the view hierarchy:
[dragCellView addGestureRecognizer: lpgr];
[self.tableView.window addSubview: dragCellView];
// swap out the cell for a placeholder:
dragCellData = _dataSource[ip.row];
_dataSource[ip.row] = @"placeholder";
[self.tableView reloadRowsAtIndexPaths: @[ip]
withRowAnimation: UITableViewRowAnimationNone];
break;
}
case UIGestureRecognizerStateChanged:
{
// where should we move the placeholder to?
NSInteger insertIndex = ptInCell.y < cell.bounds.size.height / 2.0 ? ip.row : ip.row + 1;
if ( insertIndex != placeholderIndex )
{
// remove from the datasource and the tableview:
[_dataSource removeObjectAtIndex: placeholderIndex];
[self.tableView deleteRowsAtIndexPaths: @[ [NSIndexPath indexPathForRow: placeholderIndex inSection: 0] ]
withRowAnimation: UITableViewRowAnimationFade];
// adjust:
if ( placeholderIndex < insertIndex )
{
insertIndex--;
}
// insert to the datasource and tableview:
[_dataSource insertObject: @"placeholder"
atIndex: insertIndex];
[self.tableView insertRowsAtIndexPaths: @[ [NSIndexPath indexPathForRow: insertIndex inSection: 0] ]
withRowAnimation: UITableViewRowAnimationFade];
}
// move our dragCellView
CGRect f = dragCellView.frame;
f.origin.y = pt.y - dragCellOffset;
dragCellView.frame = f;
break;
}
case UIGestureRecognizerStateEnded:
{
// replace the placeholdercell with the cell we were dragging
[_dataSource replaceObjectAtIndex: placeholderIndex
withObject: dragCellData];
[self.tableView reloadRowsAtIndexPaths: @[ [NSIndexPath indexPathForRow: placeholderIndex inSection: 0] ]
withRowAnimation: UITableViewRowAnimationFade];
// reset state
[dragCellView removeFromSuperview];
dragCellView = nil;
dragCellData = nil;
break;
}
default:
{
break;
}
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString* cellData = _dataSource[indexPath.row];
if ( [cellData isEqualToString: @"placeholder" ] )
{
// an empty cell to denote where the "drop" would go
return [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier: nil];
}
// a cell...
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier: nil];
// our "fake" move handle & gesture recognizer
UILongPressGestureRecognizer* lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector( longPress:) ];
lpgr.minimumPressDuration = 0.3;
UILabel* dragLabelView = [UILabel new];
dragLabelView.text = @"☰";
dragLabelView.userInteractionEnabled = YES;
[dragLabelView addGestureRecognizer: lpgr];
[dragLabelView sizeToFit];
cell.textLabel.text = cellData;
if ( tableView.isEditing )
{
cell.editingAccessoryView = dragLabelView;
}
else
{
cell.accessoryView = dragLabelView;
}
return cell;
}
@end