将 UITableViewDataSource 与具有子视图的自定义单元格一起使用

Posted

技术标签:

【中文标题】将 UITableViewDataSource 与具有子视图的自定义单元格一起使用【英文标题】:Using UITableViewDataSource with Custom Cells Having Subviews 【发布时间】:2015-12-30 06:31:57 【问题描述】:

在 UITableView 中使用自定义单元格时,我得到一个奇怪的表格重叠:

问题

向下滚动并在最后两行上涂上前两行! 向上滚动,前两行在上面画了两行!

这是 UITableViewDataSource 的代码:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

    let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!;

    let cellText:String = self.items[indexPath.row];

    let subjectField:UILabel = UILabel(frame: CGRect(x:55, y: 25, width: 303, height:  25));
    
    subjectField.text = cellText;
    
    //cell.textLabel?.text = cellText;    //works fine!
    cell.addSubview(subjectField);        //fails  XX(!
    
    return cell;

这是截图:

注意:“0 9”和“1 A”是涂装! Ref:'0 9' 是 row#0 ('0') 和 row#9 ('9')

问题

为什么添加子视图会导致绘制问题? 将自定义视图绘制到单元格中的正确方法是什么?

上下文

我的实际原始代码在自定义表格视图中使用自定义单元格 此处的代码示例是原始代码的精简版本。我可以发布任何需要帮助解决此问题的内容!

【问题讨论】:

我发现您的代码存在两个明显的问题:1) dequeueReusableCellWithIdentifier: 可能返回 null,因此您需要创建一个新的单元格实例。您最好使用dequeueReusableCellWithIdentifier:forIndexPath:,它会在需要时自动分配单元格,并且2)您在重用单元格时一次又一次地添加subjectField 子视图。您应该在 XIB 中添加一次,或者检查它是否已经添加到您的代码中。 【参考方案1】:

单元格标识符的问题必须是唯一的

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

    let  cellId:String = "Cell"+String(indexPath.row)
    var cell  = tableView.dequeueReusableCellWithIdentifier(cellId)
    if (cell == nil)
        cell = UITableViewCell(style: .Default, reuseIdentifier:cellId)
    
    let cellText:String = String(indexPath.row)
    let subjectField:UILabel = UILabel(frame: CGRect(x:55, y: 25, width: 303, height:  25))

    subjectField.text = cellText

    (cell! as UITableViewCell).addSubview(subjectField)

    return cell! as UITableViewCell


【讨论】:

我吃了一惊,印象深刻和惊讶 - 你修好了!!!!!!!!!!!! (cell == nil) 是关键。感谢您在这里交流问题的根源,然后是解决方案!!!!度过了我的夜晚,谢谢!!!! :)【参考方案2】:

头晕目眩 , 创建自定义单元格并在运行时以及从 Xib 中使用 Control。

1) 在 Xib 或 Storyboard 中的 ViewController 中创建 CustomCell。

2) 为您的单元格提供标识符

3) 在tableview的cellForRowAtIndexpath数据源方法中添加以下代码

    static NSString *cellId = @"CustomIdenfier";
    CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:firstCellId];
    if (cell == nil) 
        cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        [self createCustomCell:cell atIndexPath:indexPath];
    
    [self updateCustomCell:cell atIndexPath:indexPath];
    return cell;

4) createCustomCell 方法如果在 Xib 中添加控件则不需要此方法

-(void)createCustomCell:(CustomCell*)cell atIndexPath:(NSIndexPath*)indexPath
    //Here I am adding custom label run time, you can add
    // Any control in Xib and create a reference IBOutlet for it and user here.
    UILabel *lblTitle = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, cell.contentView.frame.size.width-10, 30)];
    lblTitle.textColor = [UIColor blackColor];
    lblTitle.tag = 1;
    [cell.contentView addSubview:lblTitle];

5) updateCustomCell 方法

-(void)updateCustomCell:(CustomCell*)cell atIndexPath:(NSIndexPath*)indexPath

    UILabel *lblTitle = (UILabel*)[cell.contentView viewWithTag:1];
    [lblTitle setText:[NSString stringWithFormat:@"%i",indexPath.row]];

//编辑1 如果不使用 Storyboard,则创建 UITableviewCell 的自定义扩展。

//CustomCell.h
#import <UIKit/UIKit.h>
@interface CustomCell : UITableViewCell
@property (strong, nonatomic) UILabel *lblTitle;
@end


//CustomCell.m
#import "CustomCell.h"
@implementation CustomCell
@synthesize lblTitle;

- (void)awakeFromNib 
    NSLog(@"imgUrl:%@ txtName:%@",imgUser,txtName);
    // Initialization code


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self)
        //Setup your Cell like initialising variables and setting frames of controls 
    
    return self;


- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
    [super setSelected:selected animated:animated];
    // Configure the view for the selected state

@end

【讨论】:

我不使用情节提要。我是 100% 程序化的,对不起!谢谢你的详细回答!!! J-Dizzle,为以编程方式使用自定义单元格而编辑。【参考方案3】:

根据 Rajesh Balam 的回答,这里是我的 UITableViewDataSource 中我的原始代码的工作形式!

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

    /**********************************************************/
    /* @soln  a UNIQUE 'cellId' is the key                    */
    /**********************************************************/
    let  cellId  :String = "Cell" + String(indexPath.row);

    var cell : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellId);

    if (cell == nil)
        cell = UITableViewCell(style: .Default, reuseIdentifier:cellId); //comment this out and watch it fail!
    

    let cellText:String = self.items[indexPath.row];

    let subjectField:UILabel = UILabel(frame: CGRect(x:55, y: 25, width: 303, height:  25));

    subjectField.text = cellText;

    (cell! as UITableViewCell).addSubview(subjectField);

    return cell! as UITableViewCell;


它有效。谢谢拉杰什!!! :)

【讨论】:

以上是关于将 UITableViewDataSource 与具有子视图的自定义单元格一起使用的主要内容,如果未能解决你的问题,请参考以下文章

“TableViewController”与协议“UITableViewDataSource”的冗余一致性[重复]

分离 UITableViewDelegate 和 UITableViewDataSource 导致没有数据显示

无法调用 UITableViewDataSource 方法,调试时即使光标也无法进入这些方法

制作 UITableViewDataSource 的主视图控制器委托

关于视图的 Swift 未确认协议“UITableViewDataSource”

UITableView 和 UITableViewDataSource