我在tableView
内使用了一个按钮,按下按钮时我会得到indexPath.row
。但只有在没有scroll
的情况下才能在屏幕上显示单元格时,它才能正常工作。
一旦tableView可以滚动并且我滚动到tableview,indexPath.row
返回的是一个错误的值,我注意到最初设置20个对象,例如Check
只打印9次没有20
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
lBtnWithAction = [[UIButton alloc] initWithFrame:CGRectMake(liLight1Xcord + 23, 10, liLight1Width + 5, liLight1Height + 25)];
lBtnWithAction.tag = ROW_BUTTON_ACTION;
lBtnWithAction.titleLabel.font = luiFontCheckmark;
lBtnWithAction.tintColor = [UIColor blackColor];
lBtnWithAction.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[cell.contentView addSubview:lBtnWithAction];
}
else
{
lBtnWithAction = (UIButton *)[cell.contentView viewWithTag:ROW_BUTTON_ACTION];
}
//Set the tag
lBtnWithAction.tag = indexPath.row;
//Add the click event to the button inside a row
[lBtnWithAction addTarget:self action:@selector(rowButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
//This is printed just 9 times (the the number of cells that are initially displayed in the screen with no scroll), when scrolling the other ones are printed
NSLog(@"Check: %li", (long)indexPath.row);
return cell;
}
使用点击的索引执行某些操作:
-(void)rowButtonClicked:(UIButton*)sender
{
NSLog(@"Pressed: %li", (long)sender.tag);
}
Constants.h
#define ROW_BUTTON_ACTION 9
当indexPath.row
中有很多单元格时,rowButtonClicked
在tableView
内或设置标记的正确方法是什么?
答案 0 :(得分:7)
我对这类问题的解决方法是不要以这种方式使用标签。这是对标签的完全滥用(在我看来),并且很可能会引发麻烦(正如您所发现的那样),因为细胞会被重复使用。
通常,要解决的问题是:单元格中的一个界面与用户进行交互(例如,按下按钮),现在我们想知道哪一行该单元格目前对应,以便我们可以响应相应的数据模型。
我在我的应用程序中解决这个问题的方法是,当点击按钮或其他任何东西并从中接收控制事件或委托事件时,从界面的那一块(按钮或其他)向上走视图层次结构直到我来到单元格,然后调用表视图的indexPath(for:)
,它取一个单元格并返回相应的索引路径。控制事件或委托事件始终将接口对象作为参数包含在内,因此很容易从该对象到单元格,从那里到行。
因此,例如:
UIView* v = // sender, the interface object
do {
v = v.superview;
} while (![v isKindOfClass: [UITableViewCell class]]);
UITableViewCell* cell = (UITableViewCell*)v;
NSIndexPath* ip = [self.tableView indexPathForCell:cell];
// and now we know the row (ip.row)
[注意一种可能的替代方法是使用自定义单元子类,在该子类中有一个特殊属性,用于将行存储在cellForRowAt
中。但在我看来这完全没必要,因为indexPath(for:)
会给你完全相同的信息!另一方面,页眉/页脚没有indexPath(for:)
,所以在这种情况下我做使用存储节号的自定义子类,如在this example中(参见viewForHeaderInSection
的实现)。]
答案 1 :(得分:4)
我同意@matt认为这不是一个很好用的标签,但对他的解决方案略有不同意见。在找到单元格之前,我没有走按钮的超视图,而是选择按钮的原点,将其转换为表格视图坐标,然后向表格视图询问包含单元格的indexPath那些坐标。
我希望Apple为UITableView添加一个函数require
。这是一个普遍的需求,并且易于实施。为此,这里是UITableView的一个简单扩展,它允许您向表视图询问位于其中一个tableView的单元格内的任何视图的indexPath。
以下是Objective-C和Swift中扩展的关键代码。 GitHub上有一个名为TableViewExtension-Obj-C的工作项目,它说明了下面表格视图扩展的用法。
头文件UITableView_indexPathForView.h:
indexPathForView(_:)
UITableView_indexPathForView.m文件:
#import <UIKit/UIKit.h>
@interface UIView (indexPathForView)
- (NSIndexPath *) indexPathForView: (UIView *) view;
@end
按钮上的IBAction:
#import "UITableView_indexPathForView.h"
@implementation UITableView (UITableView_indexPathForView)
- (NSIndexPath *) indexPathForView: (UIView *) view {
CGPoint origin = view.bounds.origin;
CGPoint viewOrigin = [self convertPoint: origin fromView: view];
return [self indexPathForRowAtPoint: viewOrigin];
}
- (void) buttonTapped: (UIButton *) sender {
NSIndexPath *indexPath = [self.tableView indexPathForView: sender];
NSLog(@"Button tapped at indexpPath [%ld-%ld]",
(long)indexPath.section,
(long)indexPath.row);
}
我将其添加为文件&#34; UITableView + indexPathForView&#34;一个测试项目,以确保我得到一切正确。然后在IBAction中找到一个单元格内的按钮:
import UIKit
public extension UITableView {
func indexPathForView(_ view: UIView) -> IndexPath? {
let origin = view.bounds.origin
let viewOrigin = self.convert(origin, from: view)
let indexPath = self.indexPathForRow(at: viewOrigin)
return indexPath
}
}
我将扩展程序设置为任何 UIView,而不仅仅是按钮,以便它更具通用性。
这个扩展的好处在于你可以将它放到任何项目中,它会将新的func buttonTapped(_ button: UIButton) {
let indexPath = self.tableView.indexPathForView(button)
print("Button tapped at indexPath \(indexPath)")
}
函数添加到你的所有表视图中,而不必改变你的其他代码。
答案 2 :(得分:2)
您正在遇到细胞重用问题。
为视图创建按钮时,您可以为其设置标记,但是您可以覆盖此标记以将行号设置为该标记。
当重复使用单元格时,因为行号较长ROW_BUTTON_ACTION,您不会将标记重置为正确的行号,并且出现问题。
使用标记从视图中获取信息几乎总是一个坏主意,并且非常脆弱,正如您在此处所见。
正如马特已经说过的那样,走在等级制度是一个更好的主意。
此外,您的方法不需要以这种方式编写。如果您创建自己的自定义单元格,则不需要用于创建和添加按钮和标签的代码,您可以在xib,故事板或甚至类中的代码中执行此操作。此外,如果您使用采用索引路径的dequeue方法,您将始终获得一个回收的单元格或新创建的单元格,因此无需检查返回的单元格是否为零。