如何在iOS的uitableview中使用可重用的单元格
好。 我似乎对桌面的工作方式有了一个明确的理解。 有人请向我解释如何在桌面浏览器中重复使用单元格,特别是在滚动时? 我对此有一个主要的难点,就是当我在一个单元格中创build一个动作时,其他单元格会在我滚动时受到影响。 我试图使用一个数组作为模型的后端,但我仍然得到单元格,当没有设想。 要弄清楚的是,为什么当数组中的模型没有改变时,它们会发生改变。
一个简单的例子:
使用“like”button的表格视图单元格。 当我单击其中一个单元格中的button时,button文本更改为“不同”(到目前为止这么好)。 但是当我向下滚动时,其他单元格也显示“不同”,即使我没有select它们。 而当我向上滚动时,我原来select的单元格又改变了,新的单元格也改变了。
我似乎无法弄清楚这一点。 如果你能给我看一个可用的示例源代码,那将是非常棒的! 谢谢!
- (void)viewDidLoad { [super viewDidLoad]; likeState = [[NSMutableArray alloc]init]; int i =0; for (i=0; i<20; i++) { [likeState addObject:[NSNumber numberWithInt:0]]; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [myButton setTitle:@"Like" forState:UIControlStateNormal]; [myButton addTarget:self action:@selector(tapped:) forControlEvents:UIControlEventTouchUpInside]; myButton.frame = CGRectMake(14.0, 10.0, 125.0, 25.0); myButton.tag =indexPath.row; [cell.contentView addSubview:myButton]; if (cell ==nil) { } if ([[likeState objectAtIndex:indexPath.row]boolValue]==NO) { [myButton setTitle:@"Like" forState:UIControlStateNormal]; } else{ [myButton setTitle:@"Unlike" forState:UIControlStateNormal]; } return cell; } -(void)tapped:(UIButton *)sender{ [likeState replaceObjectAtIndex:sender.tag withObject:[NSNumber numberWithInt:1]]; [sender setTitle:@"Unlike" forState:UIControlStateNormal]; }
我假设你正在通过Storyboard
来做这件事,而且你还没有通过Interface Builder
创build你的button,你需要检查被重用的单元格是否已经有了button。
按照您当前的逻辑,您将在单元格再次出现时创build一个新的button实例。
我会build议如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; //following is required when using XIB but not needed when using Storyboard /* if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } */ //Reason: //[1] When using XIB, dequeueReusableCellWithIdentifier does NOT create a cell so (cell == nil) condition occurs //[2] When using Storyboard, dequeueReusableCellWithIdentifier DOES create a cell and so (cell == nil) condition never occurs //check if cell is being reused by checking if the button already exists in it UIButton *myButton = (UIButton *)[cell.contentView viewWithTag:100]; if (myButton == nil) { myButton = [UIButton buttonWithType:UIButtonTypeCustom]; [myButton setFrame:CGRectMake(14.0,10.0,125.0,25.0)]; [myButton setTag:100]; //the tag is what helps in the first step [myButton setTitle:@"Like" forState:UIControlStateNormal]; [myButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; [myButton addTarget:self action:@selector(tapped:andEvent:) forControlEvents:UIControlEventTouchUpInside]; [cell.contentView addSubview:myButton]; NSLog(@"Button created"); } else { NSLog(@"Button already created"); } if ([likeState[indexPath.row] boolValue]) { [myButton setTitle:@"Unlike" forState:UIControlStateNormal]; } else { [myButton setTitle:@"Like" forState:UIControlStateNormal]; } return cell; }
-(void)tapped:(UIButton *)sender andEvent:(UIEvent *)event { //get index NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:currentTouchPosition]; //toggle "like" status if ([likeState[indexPath.row] boolValue]) { [likeState replaceObjectAtIndex:indexPath.row withObject:@(0)]; [sender setTitle:@"Like" forState:UIControlStateNormal]; } else { [likeState replaceObjectAtIndex:indexPath.row withObject:@(1)]; [sender setTitle:@"Unlike" forState:UIControlStateNormal]; } }
最大的问题是每次更新单元格时都会创buildbutton。
例如,如果你在屏幕上有这样可见的4条鱼:
*-----------------------* | cell A with button | *-----------------------* | cell B with button | *-----------------------* | cell C with button | *-----------------------* | cell D with button | *-----------------------*
现在,当您向下滚动,单元格A不再可见时,它将被重用并置于下面:
*-----------------------* | cell B with button | *-----------------------* | cell C with button | *-----------------------* | cell D with button | *-----------------------* | cell A with button | *-----------------------*
但对于单元格A,它又被称为cellForRowAtIndexPath
。 你做了什么是另一个button上。 所以你实际上有:
*-----------------------* | cell B with button | *-----------------------* | cell C with button | *-----------------------* | cell D with button | *-----------------------* | cell A with 2 buttons | *-----------------------*
你可以看到你很快就会有很多button堆积起来。 你可以通过@Timur Kuchkarovbuild议的故事板来解决这个问题,或者你通过修复你的代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; if (cell ==nil) { UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [myButton setTitle:@"Like" forState:UIControlStateNormal]; [myButton addTarget:self action:@selector(tapped:) forControlEvents:UIControlEventTouchUpInside]; myButton.frame = CGRectMake(14.0, 10.0, 125.0, 25.0); myButton.tag = 10; [cell.contentView addSubview:myButton]; } UIButton * myButton = (UIButton * )[cell.contentView viewWithTag:10] if ([[likeState objectAtIndex:indexPath.row]boolValue]==NO) { [myButton setTitle:@"Like" forState:UIControlStateNormal]; } else{ [myButton setTitle:@"Unlike" forState:UIControlStateNormal]; } return cell; }
通过这种方式,只需添加1个button,如果单元格不被重用(所以它没有任何内容)。
这样,你不能依靠羊肉标签号码的function挖掘,(我不会),所以你必须改变它。
这部分未经testing:
你可以检查button的父母看它所属的巫婆单元格。
UITableViewCell * cell = [[button superview] superview] /// superview of button is cell.contentView NSIndexPath * indexPath = [yourTable indexPathForCell:cell];
要重新使用单元格,请将您的单元标识符值放入界面构build器中。
首先,当你点击单元格button时,你总是将@(1)([NSNumber numberWithInt:1],最好使用@(YES)或@(NO))。 这就是为什么你会看到不正确的结果。 然后,你总是添加button到你的单元格,所以如果它被重复使用10次,你会在那里添加10个button。 为此,最好使用xib或storyboard原型。
Swift 2.1版本接受的答案。 对我很好。
override func viewDidLoad() { super.viewDidLoad(); self.arrayProducts = NSMutableArray(array: ["this", "that", "How", "What", "Where", "Whatnot"]); //array from api for example var i:Int = 0; for (i = 0; i<=self.arrayProducts.count; i++){ let numb:NSNumber = NSNumber(bool: false); self.arrayFavState.addObject(numb); //array of bool values } }
TablView数据源方法::
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("SubCategoryCellId", forIndexPath: indexPath) as! SubCategoryCell; cell.btnFavourite.addTarget(self, action: "btnFavouriteAction:", forControlEvents: UIControlEvents.TouchUpInside); var isFavourite: Bool!; isFavourite = self.arrayFavState[indexPath.row].boolValue; if isFavourite == true { cell.btnFavourite.setBackgroundImage(UIImage(named: "like-fill"), forState: UIControlState.Normal); } else { cell.btnFavourite.setBackgroundImage(UIImage(named: "like"), forState: UIControlState.Normal); } return cell; } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.arrayProducts.count; }
button操作方法::
func btnFavouriteAction(sender: UIButton!){ let position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableProducts) let indexPath = self.tableProducts.indexPathForRowAtPoint(position) let cell: SubCategoryCell = self.tableProducts.cellForRowAtIndexPath(indexPath!) as! SubCategoryCell //print(indexPath?.row) //print("Favorite button tapped") if !sender.selected { cell.btnFavourite.setBackgroundImage(UIImage(named: "like-fill"), forState: UIControlState.Normal); sender.selected = true; self.arrayFavState.replaceObjectAtIndex((indexPath?.row)!, withObject:1); } else { cell.btnFavourite.setBackgroundImage(UIImage(named: "like"), forState: UIControlState.Normal); sender.selected = false; self.arrayFavState.replaceObjectAtIndex((indexPath?.row)!, withObject:0); } }
我需要看你的代码,但我可以说你没有改变你的模型,或者你改变了你的数组中的所有行。
你可以使用从UITableViewCell扩展的一些类,在“cellForRowAtIndexPath”方法中使用它作为可重用的单元格。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"]; // Configure the cell... MyModel *model = [_models objectAtIndex:indexPath.row]; cell.nameLabel.text = model.name; cell.image.image = model.image; cell.likeButton.text = model.likeButtonText; return cell; }
然后在你的“didSelectRowAtIndexPath”方法中改变“model.likeButtonText”。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ MyCell cell* = [tableView cellForRowAtIndexPath:indexPath]; MyModel *model = [_models objectAtIndex:indexPath.row]; model.likeButtonText = [model.likeButtonText isEqual:@"like"]?@"unlike":@like; cell.likeButton.text = model.likeButtonText; }
这将更新您的单元格