滚动 UITableView 和 UICollectionView 的数据不正确
Incorrect data on scrolling UITableView and UICollectionView
我已将我的示例项目附加到 github 并在下面提供了 link
我有一个 table 视图并且在那个 table查看单元格由一个UICollectionView组成。这意味着每个单元格都可以水平滚动到一定限度,比方说 5。
tableView 单元格和 collectionview 单元格都有自定义单元格 类
table视图单元格也有一个 UIPageControl,当我们水平滚动 UICollectionViewCells 时它会改变
我设法完成了这部分工作,但假设我已经将第 2 个 table 视图单元格的集合视图滚动到第 3 个位置,这在第 9 个 table 视图单元格上重复了一些.
第 9 个 table 视图单元格也有相同的数据。但是我在 9 号还没有设置任何东西。
所以这意味着问题是可重用性和滚动时数据不正确的问题。
到目前为止我的代码是
//ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
实施Class
//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
视图有点像
我担心的是,每当我进行任何更改时,让我们在 table viewcell 上的单元格 1 上说,并将其中的集合滚动到让我们说第二个索引,然后每当我滚动完整 table
注意: 我将 table 的单元格数量保持为 10,以查看重复的影响。
我的示例项目的Githublink是https://github.com/RajanMaheshwari/TableAndCollection
首先:
[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCollectionViewCell" forIndexPath:indexPath]
总是returns一个视图,所以你不需要那个:
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 个实例(取决于行高)将在整个 table.
您需要在视图之外保留呈现每一行所必需的重要变量,并根据这些变量配置视图。
在您的情况下,您应该为每一行保留 pageControl 的页面索引 - 为此使用 NSDictionary 并为 UITableView 中的每个 indexPath 保留一个 NSNumber。
每当页面发生变化时,更新此 NSDictionary 中的值(默认为零)。
当您创建一个带有集合视图的单元格时,根据您在 NSDictionary 中为此 indexPath
所拥有的内容,为 pageControl 设置适当的值
我已将我的示例项目附加到 github 并在下面提供了 link
我有一个 table 视图并且在那个 table查看单元格由一个UICollectionView组成。这意味着每个单元格都可以水平滚动到一定限度,比方说 5。
tableView 单元格和 collectionview 单元格都有自定义单元格 类
table视图单元格也有一个 UIPageControl,当我们水平滚动 UICollectionViewCells 时它会改变
我设法完成了这部分工作,但假设我已经将第 2 个 table 视图单元格的集合视图滚动到第 3 个位置,这在第 9 个 table 视图单元格上重复了一些.
第 9 个 table 视图单元格也有相同的数据。但是我在 9 号还没有设置任何东西。
所以这意味着问题是可重用性和滚动时数据不正确的问题。
到目前为止我的代码是
//ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
实施Class
//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
视图有点像
我担心的是,每当我进行任何更改时,让我们在 table viewcell 上的单元格 1 上说,并将其中的集合滚动到让我们说第二个索引,然后每当我滚动完整 table
注意: 我将 table 的单元格数量保持为 10,以查看重复的影响。
我的示例项目的Githublink是https://github.com/RajanMaheshwari/TableAndCollection
首先:
[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCollectionViewCell" forIndexPath:indexPath]
总是returns一个视图,所以你不需要那个:
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 个实例(取决于行高)将在整个 table.
您需要在视图之外保留呈现每一行所必需的重要变量,并根据这些变量配置视图。
在您的情况下,您应该为每一行保留 pageControl 的页面索引 - 为此使用 NSDictionary 并为 UITableView 中的每个 indexPath 保留一个 NSNumber。 每当页面发生变化时,更新此 NSDictionary 中的值(默认为零)。 当您创建一个带有集合视图的单元格时,根据您在 NSDictionary 中为此 indexPath
所拥有的内容,为 pageControl 设置适当的值