Как ограничить переупорядочение строк UITableView до раздела

121

Я бился головой об этом, а Google ничего не показывал. В конце концов я решил это и подумал, что напишу это здесь для следующего человека.

У вас есть UITableViewнесколько разделов. Каждый раздел однороден, но в целом таблица неоднородна. Таким образом, вы можете разрешить переупорядочивание строк внутри раздела, но не между разделами. Может быть, вы даже хотите, чтобы один раздел вообще можно было переупорядочить (это был мой случай). Если вы смотрите, как и я, UITableViewDataSourceDelegateвы не найдете уведомления о том, когда он собирается позволить вам перемещать строку между разделами. Вы получаете один, когда он начинает перемещать строку (что нормально), и один, когда он уже переместил ее, и у вас есть возможность синхронизироваться со своими внутренними данными. Не полезно.

Так как же предотвратить повторный заказ между разделами?

Я опубликую то, что я сделал, как отдельный ответ, оставив его открытым, чтобы кто-то другой опубликовал еще лучший ответ!

philsquared
источник
1
Какое уведомление вы имеете в виду, когда говорите «вы получаете его, когда оно начинает перемещать строку»? Я не вижу одного, но надеюсь заметить, когда начнется переупорядочение ячеек.
TomSwift

Ответы:

181

Эта реализация предотвратит переупорядочение за пределами исходного раздела, как ответ Фила, но также привяжет запись к первой или последней строке раздела, в зависимости от того, где произошло перетаскивание, а не где оно началось.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
  if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
    NSInteger row = 0;
    if (sourceIndexPath.section < proposedDestinationIndexPath.section) {
      row = [tableView numberOfRowsInSection:sourceIndexPath.section] - 1;
    }
    return [NSIndexPath indexPathForRow:row inSection:sourceIndexPath.section];     
  }

  return proposedDestinationIndexPath;
}
Джейсон Харвиг
источник
Есть ли способ предотвратить автоматическую прокрутку таблицы (при перетаскивании ячейки) за пределы разрешенного раздела?
Палимондо
1
В Xamarin метод-оболочка UIKit.UITableViewController.CustomizeMoveTarget, если кому интересно.
bunkerdive
74

На самом деле, достаточно просто.

UITableViewDelegate имеет метод:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Это вызывается, когда пользователь наводит курсор на потенциальную точку сброса. У вас есть возможность сказать: «Нет! Не роняйте его сюда! Вместо этого бросайте сюда». Вы можете вернуть другой путь индекса к предложенному.

Все, что я сделал, это проверил, совпадают ли индексы разделов. Если они это сделают, то отлично, верните предложенный путь. если нет, верните исходный путь. Это также прекрасно предотвращает смещение строк в других разделах даже при перетаскивании - и перетаскиваемая строка вернется в исходное положение, если вы попытаетесь переместить ее в другой раздел.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
philsquared
источник
Выполнение именно этого действия вызывает некоторые действительно странные ошибки отображения в моей настройке, и это заметно отличается от кода собственного примера Apple о том, как это сделать. FWIW! не говорю, что это неправильно, просто мне интересно, действительно ли это сложнее, чем это.
Билли Грей
Я могу перетащить строку в другой раздел, даже если эта строка там не установлена. но это видно когда другим насильно.? любая идея
Сэнди
27

Быстрая версия ответа Джейсона для вас, ленивых:

Swift 3, 4 и 5

override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return IndexPath(row: row, section: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}

Swift 1 и 2

override func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath, toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return NSIndexPath(forRow: row, inSection: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}
Александр Норвегии
источник
7

Вы можете предотвратить перемещение строк между разделами, используя метод ниже. Только не допускайте никакого движения между секциями. Вы даже можете управлять перемещением определенной строки в разделе. например, последняя строка в разделе.

Вот пример:

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {

    // Do not allow any movement between section
    if ( sourceIndexPath.section != proposedDestinationIndexPath.section) {
        return sourceIndexPath;
    }
    // You can even control the movement of specific row within a section. e.g last row in a     Section

    // Check if we have selected the last row in section
    if (sourceIndexPath.row < sourceIndexPath.length) {
        return proposedDestinationIndexPath;
    } 
    else {
        return sourceIndexPath;
    }
}
ASM11
источник
7

Swift 3:

override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return IndexPath(row: row, section: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}
Генри
источник
3

Чем @Jason Harwig, приведенный ниже код работает правильно.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
    {
      if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
        NSInteger row = 0;
        if (sourceIndexPath.section < proposedDestinationIndexPath.section) {
          row = [tableView numberOfRowsInSection:sourceIndexPath.section] - 1;
        }
        return [NSIndexPath indexPathForRow:row inSection:sourceIndexPath.section];     
      }

      return proposedDestinationIndexPath;
    }
Bkillnest
источник
1

Чтобы не менять положение между разделами Swift3

override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if originalIndexPath.section != proposedIndexPath.section
    {
        return originalIndexPath
    }
    else
    {
        return proposedIndexPath
    }
}
ayalcin
источник