Проверьте, существует ли UIButton уже в UITableViewCell

Для каждого UITableViewCell я создаю UIButton в таблице <table> tableView: (UITableView *) tableView willDisplayCell: (UITableViewCell *) для методаRowAtIndexPath . Я хочу проверить, существует ли UIButton при его создании, поэтому он не добавляется несколько раз, но я не могу. Вот мой код:

- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) {
        [cell addSubview:cellBottomLine];
    }

        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png" highlightedImageName:@"copyCellButtonPressed.png" target:self selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
    if (!copyButton.superview) {
        [cell addSubview:copyButton];
    }

    return cell;
}
0
Я пойду с предложением Кубы, что вы можете добавить кнопку, проверяя, не является ли ячейка нулевым способом, и не будет избыточности.
добавлено автор rptwsthi, источник
почему вы не добавляете кнопку в методе cellForRowAtIndexPath: ?
добавлено автор kuba, источник

6 ответы

Я думаю, вы должны использовать метод cellForRowAtIndexPath для добавления любых подзонов в ячейку, чтобы ячейка была повторно использована при прокрутке вперед и назад, и вы не требуете проверки перед добавлением subviews в ячейку.

1
добавлено
К сожалению, при использовании предложенного вами метода, когда UITableView прокручивается из содержимого представления, состояние UIButtons сбрасывается.
добавлено автор Sergey Grischyov, источник
Чтобы решить проблему с кнопкой сброса, я считаю, что обычной методикой является создание массива ячеек в viewDidLoad (или пользовательская подпрограмма, вызывающая вызов viewDidLoad ), затем используйте cellForRowAtIndexPath , чтобы просто отобразить ячейку по этому индексу в массиве. Насколько я понимаю, помещение ячеек в массив приведет к их сохранению, даже если эта ячейка не находится на экране, поэтому UIControls не воссоздаются (и, следовательно, сбрасываются), когда ячейка повторно отображается.
добавлено автор GeneralMike, источник
Тогда в вашем методе cellForRowAtIndexPath должна быть некоторая ошибка. Вы использовали идентификатор повторного использования в этом методе?
добавлено автор HRM, источник
- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) 
    {
        [cell addSubview:cellBottomLine];
    }

    for (UIView *view in [cell subviews]) 
    {
        if ([view isKindOfClass:[UIButton class]]) 
        {
             return cell;
        }
    }

    copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png"
                                          highlightedImageName:@"copyCellButtonPressed.png"
                                                        target:self
                                                      selector:@selector(copyPressedFromCell:)];
    [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
    copyButton.tag = indexPath.row;
    if (!copyButton.superview)
    {
        [cell addSubview:copyButton];
    }

    return cell;
}
1
добавлено
Ваш ответ работает, но, как ни странно, каждый раз, когда ячейка перемещается из размера UITableView, она добавляет 1 subview в свой код cell.subviews . Любые идеи о том, что это может быть?
добавлено автор Sergey Grischyov, источник
это может быть образ «cellBottomLine», который вы добавляете, который будет добавляться каждый раз, когда вызывается функция. Я написал код специально для представления UIButton, как вы просили. Но если вы не хотите добавлять imageView либо (если он уже существует), то дайте мне знать. Я отредактирую свой ответ.
добавлено автор Harshit Gupta, источник

Ответ Ставаша лучший, но если вы не хотите этого делать, вы также можете использовать tableView: cellForRowAtIndexPath: . Я видел, что вы пробовали это и что состояние кнопки было потеряно во время прокрутки. Я предполагаю, что это связано с повторным использованием клеток. При повторном использовании ячеек, как только ячейка просмотра таблицы выходит из экрана, она кэшируется с идентификатором, а затем следующая ячейка, которая появляется на экране, извлекает ячейку с заданным идентификатором из кеша.

Чтобы избежать нажатия кнопки при ее выключении, вы можете использовать несколько идентификаторов повторного использования и сохранять состояния ваших кнопок в массиве. Мы назовем это свойство buttonStates (он должен быть изменчивым массивом).

Инициализируйте переменную buttonStates и добавьте строки для представления «базовых состояний». Добавьте столько строк, сколько количество ячеек в вашей таблице (я предполагаю, что на вашем коде есть только один раздел).

Когда состояние изменяется (это, вероятно, произойдет в вашем методе copyPressedFromCell: ), обновите объект по индексу тега кнопки (который вы уже установили в индекс ячейки) со строкой, представляющей новое состояние.

Со всем этим сделайте так, чтобы ваш метод cellForRowAtIndexPath: выглядел следующим образом:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *CellIdentifier = self.buttonStates[indexPath.row];
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

Прежде чем продолжить, давайте взглянем на некоторые из вашего кода willDisplayCell: (который следует переместить здесь).

UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
if (cellBottomLine.subviews) {
    [cell addSubview:cellBottomLine];
}

Почему вы используете этот оператор if? Если вы только что создали новое представление изображения, оно будет возвращать YES каждый раз (при условии, что массив subviews по умолчанию не является nil ). Вы предпочли бы проверить, существует ли изображение нижней ячейки в подзонах соты. Но нам даже этого не нужно. Просто добавьте изображение в метод cellForRowAtIndexPath: , внутри ! Cell if. Таким образом, мы добавим bottomCellImage , если ячейка еще не создана.

То же самое можно сказать о вызове if (! CopyButton.superview) . Продолжая, где мы находимся в нашем методе cellForRowAtIndexPath: :

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
        [cell addSubview:cellBottomLine];

        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png"
                                      highlightedImageName:@"copyCellButtonPressed.png"
                                                    target:self
                                                  selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
        [cell addSubview:copyButton];
    }

    UIButton *button = [cell viewWithTag:indexPath.row];//Get the copy button
   //Update the state of the button here based on CellIdentifier, outside the if statement so that it gets updated no matter what
   //Also configure your cell with any non-button related stuffs here

    return cell;
}
1
добавлено
Виноват. Спасибо за подавляющее объяснение, я попробую!
добавлено автор Sergey Grischyov, источник
Зачем создавать образ cellBottomLine дважды? Где нам нужно buttonStates позже в коде?
добавлено автор Sergey Grischyov, источник
Даже если я установил copyButton.highlighted = YES , где у вас есть строка UIButton * button = [cell viewWithTag: indexPath.row] , если таблица прокручивается - она ​​по-прежнему становится подсвеченный. Это начинает сводить меня с ума
добавлено автор Sergey Grischyov, источник
@SergiusGee Я не создаю его дважды, я процитировал ваш код, чтобы показать вам, как его изменить. Я объяснил, где использовать buttonStates в другом месте вашего кода.
добавлено автор aopsfan, источник
@SergiusGee не проблема, дайте мне знать, каковы ваши результаты, у меня не было времени, чтобы сделать пример приложения и проверить его сам. :)
добавлено автор aopsfan, источник
@SergiusGee Я не думаю, что выделено является правильным свойством. Попробуйте selected .
добавлено автор aopsfan, источник

Попробуйте следующим образом

if ([cell viewWithTag:LBL_TAG])
{
    UIView *vi = (UIView*)[cell viewWithTag:LBL_TAG];
    if ([vi isKindOfClass:[UILabel class]])
    {
        UILabel *lbl = (UILabel*)vi;
        NSLog(@"test  %@..",lbl.text);
    }
}

Надеюсь, это может вам помочь.

0
добавлено

Чтобы избежать этого вообще, почему бы не подкласс UITableViewCell и не создать назначенное представление этого класса в раскадровке/XIB? Таким образом, когда ячейки повторно используются, ОС не будет создавать элементы интерфейса снова и снова, а скорее повторно использовать те, которые уже были выделены из IBOutlets.

0
добавлено
@WolfgangSchreurs Это отличная идея, но это приносит большую сложность в приложении - мне придется управлять данными между двумя классами и передавать их между ними.
добавлено автор Sergey Grischyov, источник
@WolfgangSchreurs, вот что я пытаюсь сделать здесь
добавлено автор Sergey Grischyov, источник
Да, может быть, но создание раскадровки для ячейки, нет, это не то, как я хотел бы это сделать;) Спасибо в любом случае!
добавлено автор Sergey Grischyov, источник
Как правило, да. Вы когда-нибудь сливали XIB? Или раскадровки? Полагаю, что код в коде - отличный способ сделать что-то, я думаю, и он более надежный.
добавлено автор Sergey Grischyov, источник
Я не использую XIB или Раскадровки
добавлено автор Sergey Grischyov, источник
Вы также можете создать подкласс UITableViewCell в коде. Почему бы не выбрать такой подход?
добавлено автор Wolfgang Schreurs, источник
@SergiusGee хорошо, если это то, что вы пытаетесь сделать, вы делаете это неправильно :) - Вам следует создать новый класс, например. назовите его BSButtonCell и наследуйте его от UITableViewCell. Настройте кадры вашей кнопки/изображения либо в инициализаторе, либо в методе -layoutSubviews для BSButtonCell. Удалите из вашего контроллера вида метод -tableView: willDisplayCell: atIndexPath: . Настроить метод действия кнопки в -tableView: cellForRowAtIndexPath: .
добавлено автор Wolfgang Schreurs, источник
@SergiusGee Хороший дизайн и сложность почти всегда сталкиваются на первом этапе создания приложения. Когда есть ошибки или проблемы с производительностью, вот где плохой дизайн возвращается, чтобы преследовать вас.
добавлено автор Stavash, источник
Если вы собираетесь использовать идентичное графическое представление для элемента пользовательского интерфейса, как правило, я бы сказал, постройте его с помощью IB (также потребуется подкласс в коде). Я не говорю, что чистый код без IB ошибочен, мне просто не нравится, когда разработчики говорят: «Я не делаю раскадровки».
добавлено автор Stavash, источник
Конечно, рад помочь. Удачи
добавлено автор Stavash, источник
И вот что-то связанное, о котором я просил давно, просто чтобы убедиться, что я разделяю ваш гнев stackoverflow.com/questions/11538510/…
добавлено автор Stavash, источник
Чтобы ответить на вопрос о слиянии - да, я знаю о головной боли, связанной с совместной работой и файлами на основе XML, такими как раскадровки, xibs и файлы проекта. Но я не думаю, что это достаточно хороший повод для игнорирования их вообще. Например, независимо от того, как вы решите решить эту конкретную проблему, она будет гораздо менее изящной, чем реализация вашей ячейки в Interface Builder.
добавлено автор Stavash, источник
Как правило? Принцип? Что вы имеете в виду?
добавлено автор Stavash, источник
you can check it in this way:
1) put somewhere `copyButton = nil;` (in viewDidLoad, or somewhere else;
2) then:
- (UITableViewCell *)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

        UIImageView *cellBottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, CELL_HEIGHT, 320.0, 1)];
        cellBottomLine.image = [UIImage imageNamed:@"bottomCellImage.png"];
    if (cellBottomLine.subviews) {
        [cell addSubview:cellBottomLine];
    }
    if (!copyButton) {
        copyButton = [BSFunctions createButtonWithNormalImageNamed:@"copyCellButton.png" highlightedImageName:@"copyCellButtonPressed.png" target:self selector:@selector(copyPressedFromCell:)];
        [copyButton setFrame:CGRectMake(250, 10, 62, 32.5)];
        copyButton.tag = indexPath.row;
        if (!copyButton.superview) {
           [cell addSubview:copyButton];
        }
     }

    return cell;
}
0
добавлено
@Jeepston, вы ошибаетесь, это не должно.
добавлено автор Sergey Grischyov, источник
К сожалению, он не работает, он создает кнопку только в первой ячейке
добавлено автор Sergey Grischyov, источник
Второе, если должно быть, если (! CopyButton) ...
добавлено автор Jeepston, источник
Mobile Dev Jobs — вакансии и аналитика
Mobile Dev Jobs — вакансии и аналитика
6 187 участник(ов)

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin и т.д. ВАЖНО: Правила публикации и правила канала: Ссылка – https://telegra.ph/Pravila-oformleniya-vakansij-i-rezyume-11-09-2

iOS Developers — русскоговорящее сообщество
iOS Developers — русскоговорящее сообщество
2 400 участник(ов)

Общаемся на темы, посвященным iOS-разработке, Swift, Objective-C, SDK, Rx, Cocoa и т.д.