UITableView滚动问题

发布于 2024-12-05 08:49:47 字数 108 浏览 1 评论 0原文

我有一个带有自定义单元格的 TableView,其中一些有图像,另一些则没有。一切正常,但当我开始滚动时,单元格无法正确显示(图像被放置在“错误”的单元格中并在中间被剪切)。现在有人如何解决这个问题吗?

I have a TableView with custom cells, some of which have images and others don't have. Everything works fine but when I start scrolling the cells aren't showing correctly (the images are placed in "wrong" cells and cut in the middle). Does anyone now how to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅语花开 2024-12-12 08:49:47

要理解的关键是表格的单元格是重复使用的。这样做是为了提高滚动性能,因为创建新单元格(即视图)非常昂贵。

在 cellForRowAtIndexPath 方法中,您返回一个单元格。使用出列方法的现有单元,或者创建一个新单元。在该单元格上,您可以设置您想要表示的任何内容的所有属性。

我的猜测是您直接在单元格上设置这些属性,例如图像等。然后,当您滚动时,该单元格将被重复使用,并且您会再次看到相同的图像,但在错误的单元格上。

因此,您需要一个像 NSArray 这样的单独索引来维护模型对象。该模型对象包含图像等的所有细节。

让我们举个例子。我有一个包含 10 个对象的数组,其中前五个是图像“a.png”,后五个是“b.png”。

如果我收到 cellForRowAtIndexPath 的回调,我想要执行以下操作:

cellForRowAtIndexPath:(0,0) 从数组中提供索引为 0 的对象,即 a.png
cellForRowAtIndexPath:(0,1) 从数组中提供索引为 1 的对象,即 a.png
cellForRowAtIndexPath:(0,2) 从数组中提供索引为 2 的对象,即 a.png
cellForRowAtIndexPath:(0,3) 从数组中提供索引为 3 的对象,即 a.png
cellForRowAtIndexPath:(0,4) 从数组中提供索引为 4 的对象,即 a.png
cellForRowAtIndexPath:(0,5) 从数组中提供索引为 5 的对象,即 b.png
cellForRowAtIndexPath:(0,6) 从数组中提供索引为 6 的对象,即 b.png
cellForRowAtIndexPath:(0,7) 从数组中提供索引为 7 的对象,即 b.png
cellForRowAtIndexPath:(0,8) 从数组中提供索引为 8 的对象,即 b.png
cellForRowAtIndexPath:(0,9) 从数组中提供索引为 9 的对象,即 b.png

现在,让我们考虑在 UITableView 的底层,有 5 个单元格被重用。

对于上面的每个调用,都会发生以下情况:

cellForRowAtIndexPath:(0,1) 从数组中提供索引为 1 的对象,即 a.png
-- 您尝试使现有单元出列,但它返回“nil”,因此您创建了一个新单元。您设置模型对象的详细信息。

cellForRowAtIndexPath:(0,2) 从数组中提供索引为 2 的对象,即 a.png
-- 您尝试使现有单元出列,但它返回“nil”,因此您创建了一个新单元。您设置模型对象的详细信息。

cellForRowAtIndexPath:(0,3) 从数组中提供索引为 3 的对象,即 a.png
-- 您尝试使现有单元出列,但它返回“nil”,因此您创建了一个新单元。您设置模型对象的详细信息。

cellForRowAtIndexPath:(0,4) 从数组中提供索引为 4 的对象,即 a.png
-- 您尝试使现有单元出列,但它返回“nil”,因此您创建了一个新单元。您设置模型对象的详细信息。

cellForRowAtIndexPath:(0,5) 从数组中提供索引为 5 的对象,即 b.png
-- 您尝试使现有的单元出列并且它起作用了!您可以通过设置模型对象的详细信息再次使用该单元

cellForRowAtIndexPath:(0,6) 从数组中提供索引为 6 的对象,即 b.png
-- 您尝试使现有的单元出列并且它起作用了!您可以通过设置模型对象的详细信息再次使用该单元

cellForRowAtIndexPath:(0,7) 从索引 7 的数组中提供对象,即 b.png
-- 您尝试使现有的单元出列并且它起作用了!您可以通过设置模型对象的详细信息再次使用该单元

cellForRowAtIndexPath:(0,8) 从数组中提供索引为 8 的对象,即 b.png
-- 您尝试使现有的单元出列并且它起作用了!您可以通过设置模型对象的详细信息再次使用该单元

cellForRowAtIndexPath:(0,9) 从数组中提供索引为 9 的对象,即 b.png
-- 您尝试使现有的单元出列并且它起作用了!您可以通过设置模型对象的详细信息再次使用该单元

抱歉这么冗长!我希望这有帮助。也许值得学习一个好的表视图教程。肯定会有很多人。

The key thing to understand is that your table's cells are reused. This is done to increase the performance for scrolling because creating a new cell - which is a view - is quite expensive.

In the method cellForRowAtIndexPath, you return a cell. Either an existing cell using the dequeue method, or you create a new one. On that cell, you set all the properties of whatever it is you wish to represent.

My guess is that you are setting these properties such as image, etc. on the cell directly. Then when you scroll, that cell is reused and you see the same image again but on the wrong cell.

So, what you need is a separate index like an NSArray to maintain your model objects. That model object contains all the details of image, etc.

Let's take an example. I have an array with 10 objects, the first five of which are image "a.png" and the second five "b.png".

If I receive a callback of cellForRowAtIndexPath, I want to do as follows:

cellForRowAtIndexPath:(0,0) provide object from array a index 0, which is a.png
cellForRowAtIndexPath:(0,1) provide object from array a index 1, which is a.png
cellForRowAtIndexPath:(0,2) provide object from array a index 2, which is a.png
cellForRowAtIndexPath:(0,3) provide object from array a index 3, which is a.png
cellForRowAtIndexPath:(0,4) provide object from array a index 4, which is a.png
cellForRowAtIndexPath:(0,5) provide object from array a index 5, which is b.png
cellForRowAtIndexPath:(0,6) provide object from array a index 6, which is b.png
cellForRowAtIndexPath:(0,7) provide object from array a index 7, which is b.png
cellForRowAtIndexPath:(0,8) provide object from array a index 8, which is b.png
cellForRowAtIndexPath:(0,9) provide object from array a index 9, which is b.png

Now, let's consider that in the UITableView, underneath the covers, five of the cells are being reused.

For each call above, the following happens:

cellForRowAtIndexPath:(0,1) provide object from array a index 1, which is a.png
-- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.

cellForRowAtIndexPath:(0,2) provide object from array a index 2, which is a.png
-- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.

cellForRowAtIndexPath:(0,3) provide object from array a index 3, which is a.png
-- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.

cellForRowAtIndexPath:(0,4) provide object from array a index 4, which is a.png
-- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.

cellForRowAtIndexPath:(0,5) provide object from array a index 5, which is b.png
-- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object

cellForRowAtIndexPath:(0,6) provide object from array a index 6, which is b.png
-- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object

cellForRowAtIndexPath:(0,7) provide object from array a index 7, which is b.png
-- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object

cellForRowAtIndexPath:(0,8) provide object from array a index 8, which is b.png
-- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object

cellForRowAtIndexPath:(0,9) provide object from array a index 9, which is b.png
-- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object

Sorry for being so verbose! I hope this helps. Maybe it's worth working through a good table view tutorial. There will be many out there for sure.

德意的啸 2024-12-12 08:49:47

尝试更改单元格的标识符值。

NSString* identifierStr = [NSString stringWithFormat:@"ident_%d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifierStr];

Try with changing the identifier value for your cell .

NSString* identifierStr = [NSString stringWithFormat:@"ident_%d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifierStr];
忘你却要生生世世 2024-12-12 08:49:47

您可能会在创建单元格实例时添加图像,而不是在表视图请求单元格视图时添加图像。例:

这才是正确的做法。每次表视图请求单元格时,我们都会设置图像。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
    UIImageView *imageView;
    if (cell == nil) {
        cell = [UITableViewCell alloc] init ....];
        imageView = [[UIIMageView alloc] init];
        imageView.tag = 123;
        [cell addSubview:imageView];
        [imageView release];
    } else {
        imageView = [cell viewWithTag:123];
    }

    imageView.image = ...; // load image here
}

这是错误的方法。我们在创建单元格时设置图像。这将导致细胞在重复使用时出现错误的图像。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
    if (cell == nil) {
        cell = [UITableViewCell alloc] init ....];
        UIImageView *imageView = [[UIIMageView alloc] init];
        imageView.image = ...; 
        [cell addSubview:imageView];
        [imageView release];
    }

}

You probably add images when you create the cell instances, instead of when the table view asks for a cell view. Example:

This is the right way. We set the image every time the table view asks for a cell.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
    UIImageView *imageView;
    if (cell == nil) {
        cell = [UITableViewCell alloc] init ....];
        imageView = [[UIIMageView alloc] init];
        imageView.tag = 123;
        [cell addSubview:imageView];
        [imageView release];
    } else {
        imageView = [cell viewWithTag:123];
    }

    imageView.image = ...; // load image here
}

This is the wrong way. We set the image when we create the cell. This will cause cells to have wrong images when they are re-used.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
    if (cell == nil) {
        cell = [UITableViewCell alloc] init ....];
        UIImageView *imageView = [[UIIMageView alloc] init];
        imageView.image = ...; 
        [cell addSubview:imageView];
        [imageView release];
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文