У меня есть UITableViewCell
с UISwitch
как вспомогательный вид каждой ячейки. Когда я изменяю значение переключателя в ячейке, как я могу узнать, в какой строке находится переключатель? Мне нужно номер строки в событии, измененном значением переключателя.
Как узнать номер строки UITableview
Ответ 1
Тэги, подклассы или иерархия иерархии представлений работают слишком много!. Сделайте это в своем методе действий:
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
Работает с любыми типами представлений, таблицами нескольких секций, что бы вы ни выбрали - пока источник отправителя находится внутри рамки ячейки (спасибо rob!), что обычно будет иметь место.
И вот это расширение UITableView Swift:
extension UITableView {
func indexPath(for view: UIView) -> IndexPath? {
let location = view.convert(CGPoint.zero, to: self)
return self.indexPathForRow(at: location)
}
}
Ответ 2
Если вы установите для свойства tag
номер строки (как предложено другими ответами), вы должны обновлять его каждый раз в tableView:cellForRowAtIndexPath:
(поскольку ячейку можно повторно использовать для разных строк).
Вместо этого, когда вам нужен номер строки, вы можете пройти цепочку superview
из UISwitch
(или любого другого вида) в UITableViewCell
, а затем в UITableView
и спросить таблицу просмотр для пути индекса ячейки:
static NSIndexPath *indexPathForView(UIView *view) {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
if (!view)
return nil;
UITableViewCell *cell = (UITableViewCell *)view;
while (view && ![view isKindOfClass:[UITableView class]])
view = view.superview;
if (!view)
return nil;
UITableView *tableView = (UITableView *)view;
return [tableView indexPathForCell:cell];
}
Это не требует ничего в tableView:cellForRowAtIndexPath:
.
Ответ 3
в cellForRowAtIndexPath:
, установите для свойства tag
вашего элемента управления значение indexPath.row
Ответ 4
Я предпочитаю использовать subviews, если вы знаете свой макет, он обычно супер простой и 1 строка короткая...
NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
Это означает, что если он больше вложен, добавьте больше супервидов.
Бит больше информации:
все, что вы делаете, это запрос родительского представления и его родительского представления, которое является ячейкой. Затем вы запрашиваете свой tableview для указательного пути той ячейки, которую вы только что получили.
Ответ 5
Принятое решение - умный хак.
Однако зачем нам использовать hitpoint, если мы можем использовать уже имеющееся свойство tag
в UIView? Вы могли бы сказать, что тег может хранить только строку или раздел, так как его единственный Int.
Ну... Не забывайте своих корней ребята (CS101). Единственный Int может хранить два целых числа с двумя меньшими размерами. И вот расширение для этого:
extension Int {
public init(indexPath: IndexPath) {
var marshalledInt: UInt32 = 0xffffffff
let rowPiece = UInt16(indexPath.row)
let sectionPiece = UInt16(indexPath.section)
marshalledInt = marshalledInt & (UInt32(rowPiece) << 16)
marshalledInt = marshalledInt + UInt32(sectionPiece)
self.init(bitPattern: UInt(marshalledInt))
}
var indexPathRepresentation: IndexPath {
let section = self & 0x0000ffff
let pattern: UInt32 = 0xffff0000
let row = (UInt32(self) & pattern) >> 16
return IndexPath(row: Int(row), section: Int(section))
}
}
В tableView(_:, cellForRowAt:)
вы можете:
cell.yourSwitch.tag = Int(indexPath: indexPath)
И затем в обработчике действий вы можете:
func didToogle(sender: UISwitch){
print(sender.tag.indexPathRepresentation)
}
Однако учтите это ограничение: строка и раздел должны быть не большими, чем 65535. (UInt16.max)
Я сомневаюсь, что ваши индексы tableView будут такими высокими, но в случае их возникновения, бросить вызов себе и реализовать более эффективную схему упаковки. Скажем, если у нас есть очень маленький раздел, нам не нужны все 16 бит для представления раздела. У нас может быть наш внутренний макет, например:
{section area length}{all remaining}[4 BITS: section area length - 1]
то есть наши 4 LSBs указывают длину области раздела - 1, учитывая, что мы выделяем по крайней мере 1 бит для раздела. Таким образом, в случае, если наш раздел равен 0, строка может занимать до 27 бит ([1] [27] [4]), что определенно должно быть достаточно.
Ответ 6
Один из распространенных способов сделать это - установить tag
элемента управления (в вашем случае переключатель) на то, что может использоваться для идентификации строки или представляемого объекта.
Например, в tableView:cellForRowAtIndexPath:
установите свойство tag
этого переключателя на indexPath.row
, а в методе действий вы можете получить тег от отправителя.
Лично мне не нравится этот подход и предпочитаю подклассифицировать UITableViewCell. Кроме того, может быть хорошей идеей добавить "смещение" к тегу, чтобы предотвратить конфликты с тегами других представлений.
Ответ 7
Принятый ответ на этот пост совершенно прекрасен. Я хотел бы предложить читателям, что следующее, полученное из @robmayoff на этом посту, также прекрасно:
- (NSIndexPath *)indexPathForView:(UIView *)view inTableView:(UITableView *)tableView {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
UITableViewCell *cell = (UITableViewCell *)view;
return [tableView indexPathForCell:cell];
}
Некоторые утверждают, что этот подход содержит слишком много вычислительной работы из-за цикла while. Альтернатива, преобразует начало представления в пространство координат таблицы и вызывает indexPathForRowAtPoint:
, скрывает еще большую работу.
contentView
. Этот подход работает до и после такого изменения. До тех пор, пока предки могут быть найдены через цепочку супервизоров (что так же важно, как и все в UIKit), это хороший код. Ответ 8
Коллега предложил следующее, которое я сделал в категории UITableView:
+(UITableViewCell*)findParentCellForSubview:(UIView*)view
{
while (([view isKindOfClass:[UITableViewCell class]] == NO) && ([view superview] != nil))
view = [view superview];
if ([view superview] != nil)
return (UITableViewCell*)view;
return nil;
}
Все еще взломанно - но он работает.
Ответ 9
Еще один вариант использования супервизора. Работает как категория для UIView.
- (UITableViewCell *)superCell
{
if (!self.superview) {
return nil;
}
if ([self.superview isKindOfClass:[UITableViewCell class]]) {
return (UITableViewCell *)self.superview;
}
return [self.superview superCell];
}
Ответ 10
Я не знаю о нескольких разделах, но могу дать вам один раздел...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index=indexPath.row;
NSString *string=[[NSString alloc]initWithFormat:@"%ld",(long)index];
}
из этого вы можете получить номер строки, и вы можете сохранить его в строке....