#ios #objective-c #uitableview
Вопрос:
У меня есть определенные ячейки/строки в моем представлении таблицы, которые должны быть установлены в положение «выбрано» при открытии представления. В моем коде ниже, если источник данных содержит определенный идентификатор пользователя, должна появиться зеленая галочка (эта часть работает), и строка должна быть «Выбрана». Тем не менее, выбранное состояние, похоже, не работает. Как я могу установить ячейку как выбранную?
ViewController.m
-(UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
NSDictionary *client = self.sectionClients[indexPath.section][indexPath.row];
static NSString *ClientTableIdentifier = @"ClientTableViewCell";
ClientTableViewCell *cell = (ClientTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:ClientTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ClientTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSString *photo = client[@"client photo"];
cell.clientName.text = [NSString stringWithFormat:@"%@ %@", client[@"first name"], client[@"last name"]];
cell.subtext.text = client[@"phone"];
NSURL *imageUrl = [NSURL URLWithString:photo];
[cell.clientPhoto setImageWithURL:imageUrl];
if (self.selectionData != NULL amp;amp; [[self.selectionData valueForKey:@"clients ids"] containsString:client[@"nid"]])
{
cell.greenCheck.image = [UIImage imageNamed:@"added.png"];
[cell setSelected:YES];
}
return cell;
}
Комментарии:
1. По моему опыту, лучшее место для добавления любых визуальных изменений в ячейку в последнюю минуту
willDisplayCell
-это место .
Ответ №1:
Вызов setSelected
ячейки задает только выбранное состояние для этой ячейки, а не для строки в таблице. Выбранное состояние ячейки просто влияет на ее внешний вид. Это не влияет на состояние выбора самой строки.
Поскольку ячейки могут быть использованы повторно, ваша cellForRowAtIndexPath
функция также должна очистить выбранное состояние, если ячейка используется для строки, которую не следует выбирать.
Чтобы поместить a row
в выбранное состояние, вам также нужно будет вызвать selectRowAtIndexPath
каждую строку, которую вы хотите выбрать, даже те, которые в данный момент не отображаются. Поэтому вы не должны вызывать его, cellForRowAtIndexPath
потому что это будет выбирать только те строки, которые действительно были показаны.
Я не уверен, когда лучше всего было бы позвонить selectRowAtIndexPath
. Это должно быть после того, как представление таблицы вызовет numberOfRowsInSection
каждый раздел в таблице. Вы можете попробовать выбрать строки из viewDidAppear
. Если таблица в это время не готова, вам, возможно, придется отслеживать, когда numberOfRowsInSection
был вызван каждый раздел.
Ответ №2:
Многое нужно обсудить, но я хочу дать вам пару идей…
Во-первых, вам нужно сообщить табличному представлению, с помощью которого выбрана строка selectRowAtIndexPath
.
Один из способов сделать это-передать строки, которые вы хотите предварительно выбрать, в контроллер представления таблицы, а затем выбрать строки viewDidLayoutSubviews
. Обратите внимание, что viewDidLayoutSubviews
это вызывается много раз на протяжении всего жизненного цикла контроллера, поэтому вы захотите сделать это только один раз.
Кроме того, вы хотите убедиться, что отслеживаете выбранное состояние в источнике данных.
Предполагая, что мы передадим массив NSNumber
:
@interface ClientTableViewController : UITableViewController
@property (strong, nonatomic) NSArray *preSelectedRows;
@end
и используя очень простую объектную модель, такую как:
@interface ClientObject : NSObject
@property (strong, nonatomic) NSString *name;
@property (assign, readwrite) BOOL selected;
@end
вы бы установили .selected
свойство в viewDidLoad()
:
// set .selected property for rows we're going to pre-select
for (NSNumber *n in _preSelectedRows) {
clientData[[n integerValue]].selected = YES;
}
а затем, в viewDidLayoutSubviews
:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// viewDidLayoutSubviews is called many times during controller lifecycle
// so we only want to do this ONCE
if (_preSelectedRows) {
for (NSNumber *n in _preSelectedRows) {
NSIndexPath *p = [NSIndexPath indexPathForRow:[n integerValue] inSection:0];
[self.tableView selectRowAtIndexPath:p animated:NO scrollPosition:UITableViewScrollPositionNone];
}
// clear the array so we don't call this again
_preSelectedRows = nil;
}
}
Вы также можете сэкономить много усилий, если ваш класс ячеек будет обрабатывать визуальное представление. Что-то вроде этого:
@interface ClientTableViewCell()
{
UIImage *selectedImg;
UIImage *unselectedImg;
}
@end
@implementation ClientTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
selectedImg = [UIImage systemImageNamed:@"checkmark.square"];
unselectedImg = [UIImage systemImageNamed:@"square"];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.textLabel.textColor = selected ? [UIColor redColor] : [UIColor blackColor];
self.imageView.image = selected ? selectedImg : unselectedImg;
}
@end
и твоим cellForRowAt
становится просто:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ClientTableViewCell *cell = (ClientTableViewCell *)[tableView dequeueReusableCellWithIdentifier:clientTableIdentifier forIndexPath:indexPath];
// we only need to set the name, because the cell class will handle
// visual appearance when selected
cell.textLabel.text = clientData[indexPath.row].name;
return cell;
}
Вот полный пример: https://github.com/DonMag/PreSelectExample