滚动 UITableView 和 UICollectionView 的数据不正确

Posted

技术标签:

【中文标题】滚动 UITableView 和 UICollectionView 的数据不正确【英文标题】:Incorrect data on scrolling UITableView and UICollectionView 【发布时间】:2015-06-21 07:34:30 【问题描述】:

我已将我的示例项目附加到 github,并提供了下面的链接我有一个表格视图,在该表格视图中,单元格包含一个 UICollectionView。这意味着每个单元格都可以水平滚动到某个限制,比如说 5。tableView 单元格和 collectionview 单元格都有自定义单元格类tableview 单元格还有一个 UIPageControl,它会改变当我们水平滚动 UICollectionViewCells 我设法完成了这部分工作,但假设我已将第 2 个 tableview 单元格的 collectionview 滚动到第 3 个位置,并且这在第 9 个 tableview 单元格上有所重复。 第 9 个 tableview 单元格也有相同的数据。但是我在 9 号还没有设置任何东西。 所以这意味着问题在于可重用性和滚动时数据不正确。

到目前为止我的代码是

//ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@end

实现类

//ViewController.m
#import "ViewController.h"
#import "MyCollectionViewCell.h"
#import "MyTableViewCell.h"
@interface ViewController ()

    MyTableViewCell* tableViewCell;

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];




#pragma mark TableView Delegates
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:    (NSInteger)section
    return 10;


-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

   tableViewCell=(MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell"];
    if(tableViewCell==nil)
    
        tableViewCell=[[MyTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyTableViewCell"];
    

    UICollectionViewFlowLayout *flowLayout =   

 [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    [flowLayout setMinimumInteritemSpacing:0.0f];
    [flowLayout setMinimumLineSpacing:0.0f];
    [tableViewCell.collectionView setPagingEnabled:YES];
    [tableViewCell.collectionView setCollectionViewLayout:flowLayout];
    [tableViewCell.collectionView setBackgroundColor:[UIColor whiteColor]];
    tableViewCell.pageControl.tag=indexPath.row;
    tableViewCell.collectionView.tag=indexPath.row;
    NSLog(@"Index path row %ld",indexPath.row);
    [tableViewCell setSelectionStyle:UITableViewCellSelectionStyleNone];
tableViewCell.path=indexPath;

    return tableViewCell;


#pragma mark CollectionView Delegates

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

    return 5;


-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
     MyCollectionViewCell* cell=(MyCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCollectionViewCell" forIndexPath:indexPath];
    if(cell==nil)
    
        cell=[[MyCollectionViewCell alloc]initWithFrame:CGRectMake(0, 0, collectionView.frame.size.width, collectionView.frame.size.height)];
    
    [cell.myLabel setText:[NSString stringWithFormat:@"%ld",(long)indexPath.row]];
    return cell;


-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
    return collectionView.frame.size;

-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
    return UIEdgeInsetsMake(0, 0, 0, 0);


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView


    if ([scrollView isKindOfClass:[UICollectionView class]])
    
        UICollectionView *mainCollection = (UICollectionView *) scrollView;

        NSIndexPath *myIP = [NSIndexPath indexPathForRow:mainCollection.tag inSection:0];

        MyTableViewCell *cell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:myIP];

        CGRect visibleRect = (CGRect).origin = mainCollection.contentOffset, .size = mainCollection.bounds.size;
        CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
        NSIndexPath *visibleIndexPath = [mainCollection indexPathForItemAtPoint:visiblePoint];
        NSLog(@"visibleIndexPath %ld",(long)visibleIndexPath.row);


        [cell.pageControl setCurrentPage:visibleIndexPath.row];
    





@end

细胞类

//MyTableViewCell.h

#import <UIKit/UIKit.h>

@interface MyTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
@property (strong, nonatomic) NSIndexPath * path;
@end

MyCollectionViewCell.h

 //MyCollectionViewCell.h
#import <UIKit/UIKit.h>

@interface MyCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@end

视图类似于

我担心的是,每当我进行任何更改时,让我们在表格 viewcell 上的单元格 1 上说并滚动其中的集合以让我们说第二个索引,然后每当我滚动整个表格时都会重复此操作

注意:我已将表格的单元格数保持为 10,以查看重复影响。 我的示例项目的 Github 链接是https://github.com/RajanMaheshwari/TableAndCollection

【问题讨论】:

您有两种方法来维护 Tableview 状态,即一种是使用数据源表示使用模型为每一行维护状态,该模型维护其上每个视图的信息。其次,像 Grzegorz Krukowski 在下面的回答中解释的那样创建新单元格。但是第二个是更昂贵的一个。给您的一个建议是,在 tableview 单元格中的 awakefromnib 方法中移动集合视图流布局设置,同时在 awakefromnib 中移动所有默认设置代码。 嗨拉詹。你有解决这个问题的方法吗?请告诉你是否明白。 我们必须维护一个数据源以避免重复 @RajanMaheshwari 你的代码在 github 上更新了吗? @BhaveshDhaduk 我不记得它是否更新了。很久以前我在学习这些东西时发布了这个问题 【参考方案1】:

首先:

[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCollectionViewCell" forIndexPath:indexPath]

总是返回一个视图,所以你不需要那个:

if(cell==nil)

    cell=[[MyCollectionViewCell alloc]initWithFrame:CGRectMake(0, 0, collectionView.frame.size.width, collectionView.frame.size.height)];

因为它不会发生。

你真正的原因是你只有一个单元格用于所有 UITableView... 将 tableCell 保留为属性的想法来自哪里?

    MyTableViewCell* tableViewCell;

您需要为每个 indexPath 分别创建一个单元格实例,现在您有一个显示多次的实例,这就是为什么在其中一个上更改集合视图页面会影响其他行 - 因为它是同一个对象(视图) .

消除该问题后,您需要记住元素将被重用 - 这意味着您的第一行实例,在它从屏幕上消失后,您将在第 5 行再次重用,因此在元素出列后,您需要将所有变量设置到该行。 您不能将变量保留在此行中,因为它将被重复使用,因此即使您有 100 行,您也将在整个表中重复使用大约 5-6 个实例(取决于行高)。

您需要保留重要的变量,这是在视图之外渲染每一行所必需的,并基于这些变量配置视图。

在您的情况下,您应该为每一行保留 pageControl 的页面索引 - 为此使用 NSDictionary 并为 UITableView 中的每个 indexPath 保留一个 NSNumber。 每当页面发生变化时,更新此 NSDictionary 中的值(默认为零)。 当您使用集合视图创建单元格时,请根据您在 NSDictionary 中为此 indexPath 的内容为 pageControl 设置适当的值

【讨论】:

我找不到你。我必须删除双端队列.. 行吗? 我已将我的项目附加为 github 链接。你能看看并找出我的错误吗..? 好的,现在我已经在单元格中为行 MyTableViewCell* tableViewCell=(MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell"];.. 但问题仍然存在 现在代码是 -(UITableViewCell*)tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath MyTableViewCell tableViewCell=(MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@ "MyTableViewCell"]; if(tableViewCell==nil) tableViewCell=[[MyTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyTableViewCell"]; ....... 返回 tableViewCell; //问题依旧存在 抱歉迟到了..我必须维护一个数据源才能达到同样的效果..

以上是关于滚动 UITableView 和 UICollectionView 的数据不正确的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动uitableview和顶部的部分标题,可见并滚动到

如何使 UITableView 水平和垂直滚动

使用 prefersLargeTitles 和 UITableView 平滑滚动

如何同时使用 UIScrollView 和 UITableView 实现平滑滚动?

UITableView 滚动时奇怪的布局行为变化

拦截 UITableView 滚动触摸