【问题标题】:Obj-C - Set tableview row as selected on load?Obj-C - 将tableview行设置为在加载时选择?
【发布时间】:2021-10-29 12:13:39
【问题描述】:

我的 tableview 上有某些单元格/行在打开视图时应该设置为“已选择”。在我下面的代码中,如果数据源包含特定的用户 ID,则应出现绿色复选标记(此部分有效),并且该行应为“已选择”。也就是说,选定的状态似乎不起作用。如何将单元格设置为选中?

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 && [[self.selectionData valueForKey:@"clients ids"] containsString:client[@"nid"]])
    {
        
        cell.greenCheck.image = [UIImage imageNamed:@"added.png"];
    
        [cell setSelected:YES];
    }
  
        return cell;
        
    
}
    

【问题讨论】:

  • 根据我的经验,向单元格添加任何最后一分钟的视觉更改的最佳位置是willDisplayCell

标签: ios objective-c uitableview


【解决方案1】:

有很多要讨论的,但是给你一些想法......

首先,您需要使用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

您可以在viewDidLoad() 中设置.selected 属性:

// 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;
    }

}

您还可以通过让 cell 类处理视觉表示来为自己节省大量精力。像这样的:

@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

【讨论】:

    【解决方案2】:

    在单元格上调用setSelected 只会设置该单元格的选定状态,而不是表格中的一行。单元格的选定状态只会影响其外观。它不影响行本身的选择状态。

    由于单元格可以重复使用,如果单元格用于不应被选中的行,您的cellForRowAtIndexPath 函数也应该清除选中状态。

    为了将row 置于选中状态,您还需要为要选中的每一行调用selectRowAtIndexPath,即使是当前未显示的行。所以你不应该从cellForRowAtIndexPath 调用它,因为那只会选择实际显示的行。

    我不确定何时致电selectRowAtIndexPath 是最佳时间。它必须在表视图为表中的每个部分调用numberOfRowsInSection 之后。您可以尝试从viewDidAppear 中选择行。如果当时表格还没有准备好,那么您可能需要跟踪每个部分的 numberOfRowsInSection 何时被调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 1970-01-01
      • 2020-09-09
      • 1970-01-01
      • 2019-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多