UICollectionView reloadData refreshes only first item - ios

When I perform [self.collectionView reloadData];, only my first item is reloaded.
Even though - (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; is called and stores, for example, two items, then (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath is only called once for the first item.
I have verified that in numberOfItemsInSection the bounds are frame's sizes are big enough to store at least three of my items.
numberOfItemsInSection:2 frame: {{0, 0}, {400, 150}} and bounds {{0, 0}, {400, 150}}
And every UICollectionViewCell is {0, 0}, {400,45} and are stored vertically, as specified in the init method.
I have read there are several bugs with UICollectionView and ios7 but none of the previously described solutions worked for my case. I have already tried with reloadItemsAtIndexPaths and reloadSections but that did not work and sometimes gave me exceptions.
I have also tired to programatically add the items with no success:
[self.collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem: (self.currentPeripherals.count -1) inSection:0]]];
This is how my UICollectionViewController looks like:
- (instancetype)init
{
UICollectionViewFlowLayout *aFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[aFlowLayout setItemSize:CGSizeMake(400, 150)];
[aFlowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
self = [self initWithCollectionViewLayout:aFlowLayout];
if (self) {
self.view.frame=CGRectMake(0,0,400,150);
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.collectionView.backgroundView=[[UIView alloc] initWithFrame:CGRectZero];;
self.view.layer.backgroundColor=[UIColor clearColor].CGColor;
self.collectionView.backgroundColor=[UIColor clearColor];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
}
return self;
}
- (void)sharedInit {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleBTPOSHostDidUpdatePeripheralsNotification:) name:BTPOSHostDidUpdatePeripheralsNotification object:nil];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return self.currentPeripherals.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DeviceCell *deviceCell = [cv dequeueReusableCellWithReuseIdentifier:CellID forIndexPath:indexPath];
if(!deviceCell.label)
{
[deviceCell prepareForReuse];
PeripheralTracking *peripheral=self.currentPeripherals[indexPath.item];
[deviceCell configureLabelWithPeripheralTracking:peripheral forItem:indexPath.item];
[deviceCell.contentView addSubview:deviceCell.label];
}
return deviceCell;
}
- (void)handleBTPOSHostDidUpdatePeripheralsNotification:(NSNotification *)notification
{
NSUInteger oldCount = self.currentPeripherals.count;
NSDictionary *trackedPeripherals = notification.userInfo[BTPOSHostDidUpdatePeripheralsNotificationPeripheralsKey];
[self sortPeripheralsDictionary:trackedPeripherals];
[self.collectionView reloadData];
}
And this is how my peripheral devices are sorted:
-(void)sortPeripheralsDictionary:(NSDictionary*)peripheralsDictionary
{
NSMutableArray *dictValues = [[peripheralsDictionary allValues] mutableCopy];
if(dictValues.count>1)
{
[dictValues sortUsingComparator: (NSComparator)^(PeripheralTracking *a, PeripheralTracking *b)
{
NSNumber *RSSI1 = 0;
NSNumber *RSSI2 = 0;
NSComparisonResult result = 0;
if(a.averageRSSI)
{
PeripheralTrackingRSSI doubleRSSIa = a.averageRSSI;
RSSI1 = [NSNumber numberWithDouble:doubleRSSIa];
}
if(b.averageRSSI)
{
PeripheralTrackingRSSI doubleRSSIb = b.averageRSSI;
RSSI2 = [NSNumber numberWithDouble:doubleRSSIb];
}
if(RSSI1 && RSSI2)
{
result = [RSSI2 compare:RSSI1];
}
return result;
}
];
}
self.currentPeripherals = dictValues;
}

You're setting the height of each cell to 150:
[aFlowLayout setItemSize:CGSizeMake(400, 150)]
Try changing that to 45:
[aFlowLayout setItemSize:CGSizeMake(400, 45)]
Or you can implement collectionView:layout:sizeForItemAtIndexPath: if your cell size varies from cell to cell. The reason you're only seeing one call to collectionView:cellForItemAtIndexPath: is that your collection view only has room to display one cell. If you scroll it, you should see the other one.

Try using this :
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
KKMDeviceCell *deviceCell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
if(!deviceCell.label)
{
[deviceCell prepareForReuse];
[deviceCell.contentView addSubview:deviceCell.label];
}
PeripheralTracking *peripheral=self.currentPeripherals[indexPath.item];
[deviceCell configureLabelWithPeripheralTracking:peripheral forItem:indexPath.item];
return deviceCell;
}

Related

CollectionViewItem aren't allocated correctly on iPhoneX screen

My iOS application has not yet support iPhoneX layout.
That is my application doesn't have Launch Screen for iPhoneX (1124x2436, 2436x1124).
Thus on iPhoneX, UI my application is shown on 735x1334 area. It's OK.
Now I added UICollectionView on the top of my view.
I assigned the size of CollectionViewItem so that the CollectionView has 6 items horizontally.
On iPhone8(iOS11.2) the CollectionViewItems were allocated as I intended.
But on iPhoneX(iOS11.2) the CollectionView has 2 rows and first row is blank, so it's even scrollable.
I'd appreciate it if you would tell me the way to layout my collectionview as I intended.
My code is like below,
View Controller.m
- (void)loadView
{
self.view = [[FirstView alloc] init];
}
FirstView.m
- (id)init
{
self = [super init];
if (self) {
self.backgroundColor = UIColor.whiteColor;
[self initGridView];
}
return self;
}
- (void)initGridView
{
_gridView = [[GridView alloc] init];
[self addSubview:_gridView];
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self layoutGridView];
}
- (void)layoutGridView
{
CGSize parentSize = _gridView.superview.frame.size;
_gridView.frame = CGRectMake(0, 0, parentSize.width, 48);
}
GridView.m
- (id)init
{
self = [super initWithFrame:CGRectZero collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
if (self) {
self.delegate = self;
self.dataSource = self;
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class])];
self.backgroundColor = UIColor.grayColor;
}
return self;
}
#pragma mark -
#pragma mark UICollectionViewDataSource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
NSString *cellName = NSStringFromClass([UICollectionViewCell class]);
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellName forIndexPath:indexPath];
if (indexPath.row % 2 == 0) {
cell.contentView.backgroundColor = UIColor.blueColor;
}
else {
cell.contentView.backgroundColor = UIColor.orangeColor;
}
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 6;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize selfSize = self.frame.size;
CGFloat width = selfSize.width / 6;
return CGSizeMake(width, 48);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 0;
}
I've resolved the issue by adding the following line in my init() method of GridView.m file.
if #available(iOS 11.0, *) {
self.collectionView.contentInsetAdjustmentBehavior = .never
} else {
// Fallback on earlier versions
}
Thank you.

UITableView is not refreshing when scrolling

I have UITableView, with CustomCell. In CustomCell there is UICollectionView with CustomUICollectionViewCell.
Everything is created in the way, according to UICollectionView inside CustomTableCell.
Then, let's say I have 12 rows. On the beginning I can see 6 of them.
In CustomUICollectionViewCell, labels are fine, but when I scroll down, to see other cells, CustomUICollectionViewCells labels are not as expected. They are the same as first 6 rows, which are now scrolled up.
Where should I refresh CustomUICollectionViewCells label after scroll?
Example view:
Before scrolling:
After scrolling:
However when debugging, when assigning data to cell, everything is assigned fine.
All code is in the link as it's also my question.
Seems that it's duplicating rows. I guess that it should be reloaded(?).
Added prepareForReuse method, as advised, but didn't help. Now my CustomCellClass looks:
#implementation TemperatureTableViewCell
NSNumberFormatter *decimalStyleFormatter;
- (void)awakeFromNib
{
[super awakeFromNib];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(50, 50)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.collectionView = [[CollectionView alloc] initWithFrame: CGRectZero collectionViewLayout:flowLayout];
[self.collectionView registerClass:[TemperatureItemCollectionViewCell class] forCellWithReuseIdentifier:#"TemperatureItemCollectionCell"];
self.collectionView.showsHorizontalScrollIndicator = NO;
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
[self.contentView addSubview:self.collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.collection.count;
}
-(void)collectionView:(CollectionView *)collectionView willDisplayCell:(TemperatureItemCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
TemperatureSensor *temp = self.collection[indexPath.item];
cell.temperatureValue = temp.temperature.stringValue;
cell.tempValTempCollViewCell.text = [NSString stringWithFormat:#"%#°C", cell.temperatureValue];
cell.sensorName.text = temp.sensorName;
cell.imageTempCollViewCell.image = [TemperatureImageHelper getTemperatureIcon:temp];
[self.collectionView reloadData];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
TemperatureItemCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"TemperatureItemCollectionCell" forIndexPath:indexPath];
return cell;
}
- (void)setCollectionViewDelegate:(id)dataSourceDelegate indexPath:(NSIndexPath *)indexPath {
self.collectionView.delegate = dataSourceDelegate;
}
#end
And my CustomCollectionViewCell:
#implementation TemperatureItemCollectionViewCell
-(void)awakeFromNib {
[super awakeFromNib];
}
-(void)prepareForReuse {
[super prepareForReuse];
self.imageTempCollViewCell.image = nil;
self.tempValTempCollViewCell.text = nil;
self.sensorName.text = nil;
self.temperatureValue = nil;
}
#end
My TableViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (_tempSensorsDictionary == nil)
return 0;
else {
NSArray *allSensorKeys = [_tempSensorsDictionary allKeys];
return [allSensorKeys count];
}
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(TemperatureTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
[cell setCollectionViewDelegate:self indexPath:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
NSArray *nodeNumbers = [_tempSensorsDictionary allKeys];
TemperatureTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath: indexPath];
cell.collection = [_tempSensorsDictionary objectForKey:nodeNumbers[indexPath.row]];
//NSArray *nodeNumbers = [_tempSensorsDictionary allKeys];
if([[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]] != nil &&
![[[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]] isEqualToString:#""]) {
NSString *name = [NSString stringWithFormat:#"%# (%#)", [[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]], nodeNumbers[indexPath.row]];
cell.unitNameLabel.text = name;
} else {
cell.unitNameLabel.text = nodeNumbers[indexPath.row];
}
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 85.0;
}
Because UITableViewCells are reused for performance, caching can sometimes occur. In your TemperatureTableViewCell class you should override prepareForReuse and reset its properties. In your case you should clear the data you are populating it with. I would also keep prepareForReuse in TemperatureItemCollectionViewCell to avoid anymore issues.
- (void)prepareForReuse
{
[super prepareForReuse];
//Reset properties here.
self.collection = nil;
[self.collectionView reloadData];
}
I think this is what's happening. Inside of your child cell (I think it's collectionViewCell) you should reset all the values of the ui elements. Basically you are reusing one cell and you neeed to reset the values of the text or the images on it.
override func prepareForReuse() {
super.prepareForReuse()
titleLabel1.text = nil
image1.image = nil
...
}

UICollectionView reloadData doesn't work correctly

I'm face a strange problem, when I execute from an action (button) the reloadData of my UICollectionView the cells are not displayed correctly, only the background image of the cells are ok.
My "INVPropertyCell" is composed with a background image and 2 labels (title & price). When I execute the reloadData the above labels from cells disappeared randomly.
I have done a lot of searches in the different forums, some people have the same problem but I didn't find out a fix.
Below, you will find my code, if someone can help me it would be very very appreciated.
Jérôme.
- (void)viewDidLoad
{
NSLog (#"INVPropertiesViewController -- viewDidLoad");
[super viewDidLoad];
// Enregistrement de la cellule.
[self.clProperties registerNib:[UINib nibWithNibName:#"INVPropertyCell" bundle:nil] forCellWithReuseIdentifier:#"propertyCell"];
// Enregistrement du header de section
[self.clProperties registerNib:[UINib nibWithNibName:#"INVPropertyHeaderSection" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"headerCollectionCell" ];
self.clProperties.delegate = self;
self.clProperties.dataSource =self;
NSLog (#"INVPropertiesViewController -- End of viewDidLoad");
}
- (void)viewWillAppear:(BOOL)animated
{
NSLog (#"INVPropertiesViewController -- viewWillAppear");
[super viewWillAppear:animated];
categoryDictionary = [ServiceDatas getCategoriesDictionary];
tblProperties = [(NSArray*)[ServiceDatas getListPropertiesByLieuFromLocalDataStore:self.selectedResidence] mutableCopy];
if(tblProperties.count==0 & self.selectedResidence.propertiesCount.longValue >0)
tblProperties = [(NSArray*)[ServiceDatas getListPropertiesByLieuFromServer:self.selectedResidence] mutableCopy];
tblPropertiesByCategory = [ServiceDatas createCategoryBreakDown:tblProperties];
keysCategories = [tblPropertiesByCategory allKeys];
[self.clProperties reloadData];
NSLog (#"INVPropertiesViewController -- End of viewWillAppear");
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
// [self.clProperties.collectionViewLayout invalidateLayout];
return tblPropertiesByCategory.count;
}
- (UICollectionReusableView *)collectionView: (UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
UICollectionReusableView *reusableview = nil;
if(kind == UICollectionElementKindSectionHeader){
INVPropertyHeaderSection *headerSection = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"headerCollectionCell" forIndexPath:indexPath];
id categoryId = [keysCategories objectAtIndex:indexPath.section];
CategoryModel *category = categoryDictionary[categoryId];
if(category!=nil){
headerSection.backgroundColor = [Utils colorFromHexString:category.color];
headerSection.lblCategory.text = [category.title uppercaseString];
}
reusableview = headerSection;
}else if(kind == UICollectionElementKindSectionFooter){
if (reusableview==nil) {
reusableview=[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
}
}
return reusableview;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
// Return the number of rows in the section.
id categoryId = [keysCategories objectAtIndex:section];
NSMutableArray *tblProperties = [tblPropertiesByCategory objectForKey:categoryId];
return [tblProperties count];
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
INVPropertyCell *cell = nil;
id categoryId = [keysCategories objectAtIndex:indexPath.section];
NSMutableArray *tblProperties = [tblPropertiesByCategory objectForKey:categoryId];
if(tblProperties!=nil){
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"propertyCell" forIndexPath:indexPath];
PropertyModel *property = [tblProperties objectAtIndex:indexPath.item];
NSLog(#"Ligne %ld - Colonne %ld - Lieux %#",indexPath.section, (long)indexPath.item, property.title );
CategoryModel *category = categoryDictionary[categoryId];
if(category!=nil){
[cell initWithProperty:property backgroundColor:[Utils colorFromHexString:category.color]];
}
}
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
// Récupération du bien courant.
id categoryId = [keysCategories objectAtIndex:indexPath.section];
NSMutableArray *tblProperties = [tblPropertiesByCategory objectForKey:categoryId];
PropertyModel *property = [tblProperties objectAtIndex:indexPath.row];
NSLog(#"Property sélectionnée : %#",property.title);
self.selectedProperty = property;
if(property!=nil && [property.title isEqualToString:EMPTY_PROPERTY]){
self.selectedProperty = nil;
}
// Déclenche le Segue pour aller à l'écran "Property"
[self performSegueWithIdentifier:#"segueEditPropertyView" sender:self];
}
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize mElementSize = CGSizeMake(107, 106);
if(indexPath.item==0){
mElementSize = CGSizeMake(106, 106);
}
return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 0.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 0.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (IBAction)btnRefresh:(id)sender {
[self.clProperties reloadData];
}
i think,you have to register class before register nib for both INVPropertyCell and INVPropertyHeaderSection cell.
You try check and alloc cell if it is null in collectionView..cellForItemAtIndexPath
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"propertyCell" forIndexPath:indexPath];
if (cell == null) {
Array *xibs = [[NSBundle mainBundle] loadNibWithNamed:#"propertycell"
...];
cell = xibs[0];
}
I'm coding in swift, so maybe above syntax is wrong, but this is idea :)

Is it feasible to create custom CollectionViewLayout where spacing between individual cell can specifically control

I am trying to build a honeycomb using UiCollectionView . I have used https://github.com/cyrilchandelier/CCHexagonFlowLayout component for creating the basic structure of my view.
According to the requirement when any cell is tapped the adjacent cells should move out distance x from the tapped cell, with animation .
I have create two collectionViewLayout with different spacing value and changing it at didSelectItemAtIndexPath method
Here is my code …
#import "HoneycombViewController.h"
#interface HoneycombViewController ()
// Collection view
#property (nonatomic, strong) UICollectionView *collectionView;
#property(nonatomic,strong) CCHexagonFlowLayout *layout;
#property(nonatomic,strong) CCHexagonFlowLayout *largeLayout;
#property(nonatomic) CGFloat minimumItemSpacingFactor;
#property(nonatomic) CGFloat minimumLineSpacingFactor ;
#property(nonatomic) CGFloat layoutGapFactor ;
#end
#implementation A3HoneycombViewController
#synthesize minimumLineSpacingFactor,minimumItemSpacingFactor,layoutGapFactor;
- (void)viewDidLoad
{
[super viewDidLoad];
self.minimumItemSpacingFactor = 10.0f;
self.minimumLineSpacingFactor = 10.0f;
self.layoutGapFactor = 10.0f;
// Build layout
self.layout = [[CCHexagonFlowLayout alloc] init];
self.layout.delegate = self;
//layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.layout.scrollDirection = UICollectionViewScrollDirectionVertical;
self.layout.minimumInteritemSpacing = -30.0f;
self.layout.minimumLineSpacing = 10.0f;
self.layout.sectionInset = UIEdgeInsetsMake(20.0f, 15.0f, 20.0f, 15.0f);
self.layout.itemSize = RootCell_SIZE;
//layout.headerReferenceSize = HeaderView_SIZE(layout.scrollDirection);
//layout.footerReferenceSize = FooterView_SIZE(layout.scrollDirection);
self.layout.headerReferenceSize = CGSizeMake(self.view.frame.size.width,50) ;
self.layout.footerReferenceSize = CGSizeMake(self.view.frame.size.width,50) ;
self.layout.gap = 76.0f;
//create large layout
self.largeLayout = [[CCHexagonFlowLayout alloc] init];
self.largeLayout.delegate = self;
self.largeLayout.scrollDirection = self.layout.scrollDirection;
self.largeLayout.minimumLineSpacing = self.layout.minimumLineSpacing+self.minimumLineSpacingFactor;
self.largeLayout.minimumInteritemSpacing = self.layout.minimumInteritemSpacing+self.minimumItemSpacingFactor;
self.largeLayout.itemSize = self.layout.itemSize;
self.largeLayout.sectionInset = self.layout.sectionInset;
self.largeLayout.headerReferenceSize =self.layout.headerReferenceSize;
self.largeLayout.footerReferenceSize = self.layout.footerReferenceSize;
self.largeLayout.gap = self.layout.gap + self.layoutGapFactor;
// Build collection view
_collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:self.layout];
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.backgroundColor = [UIColor whiteColor];
// Register cell and views
[_collectionView registerNib:[RootCell cellNib] forCellWithReuseIdentifier:RootCell_ID];
[_collectionView registerNib:[HeaderView viewNib] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderView_ID];
[_collectionView registerNib:[FooterView viewNib] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:FooterView_ID];
// Add to view
[self.view addSubview:_collectionView];
// Reload data
[_collectionView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UICollectionDataSource methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
switch (section)
{
case 0:
return 10;
default:
return 10;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
RootCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:RootCell_ID forIndexPath:indexPath];
[cell configureWithInt:indexPath.item];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath
{
// Section header
if ([kind isEqualToString:UICollectionElementKindSectionHeader])
return [_collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:HeaderView_ID
forIndexPath:indexPath];
// Section footer
if ([kind isEqualToString:UICollectionElementKindSectionFooter])
return [_collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:FooterView_ID
forIndexPath:indexPath];
return nil;
}
-(CGSize)collectionViewContentSize { //Workaround
CGSize superSize = [self.layout collectionViewContentSize];
CGRect frame = self.collectionView.frame;
return CGSizeMake(fmaxf(superSize.width, CGRectGetWidth(frame)), fmaxf(superSize.height, CGRectGetHeight(frame)));
}
//
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayout *toLayout = self.layout == self.collectionView.collectionViewLayout ? self.largeLayout : self.layout;
[self.collectionView setCollectionViewLayout:toLayout animated:YES completion:^(BOOL finished) {
NSLog(#"animation end ");
}];
}
In the screenshot2 I have tapped in cell 1 now adjacent cells like 0 ,5,6,7,2 moved correctly as marked in green but other cells also moved marked in red .
As per this code all cell layout is changed but I want only my tabbed cell should be stick to its position and change its cell spacing show that it seems like its adjacent cells are move away at distance x also other cells in between space should remain with older value. Is it feasible to create custom CollectionViewLayout where spacing between individual cell can specifically control ? Also how we can use different CollectionViewLayout for different cells?

UICollectionView insertItemsAtIndexPaths: raising error

I know there are all sorts of questions related to this, but none of the answers answered this.
Anyways, I have a UICollectionView that should be scroll forever, but I can't seem to get insertItemsAtIndexPaths: to work. It raises the error:
*** Assertion failure in -[UICollectionView _endItemAnimations], /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:3688
Here is my code:
#import "ImageSliderViewController.h"
#define ITEM_CELL_IDENTIFIER #"ItemCell"
#interface ImageSliderViewController ()
#end
#implementation ImageSliderViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupCollectionView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - UICollectionView methods
-(void)setupCollectionView {
self.items = [[NSMutableArray alloc] init];
loadingGap = 5;
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[ImageSliderCell class] forCellWithReuseIdentifier:ITEM_CELL_IDENTIFIER];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:YES];
[self.collectionView setCollectionViewLayout:flowLayout];
[self loadMorePosts];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.items.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ImageSliderCell *cell = (ImageSliderCell *)[collectionView dequeueReusableCellWithReuseIdentifier:ITEM_CELL_IDENTIFIER forIndexPath:indexPath];
cell.imageTitle.text = [NSString stringWithFormat:#"%ld",(long)indexPath.item];
NSLog(#"%d : %d",indexPath.item,self.items.count-1);
if (indexPath.item >= self.items.count-1) {
[self loadMorePosts];
}
return cell;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = self.collectionView.frame.size;
size.height = size.height/2;
return size;
}
- (void)loadMorePosts
{
NSLog(#"Loading new items");
NSUInteger loopTill = self.items.count + loadingGap;
NSMutableArray *indexPathsToLoad = [NSMutableArray new];
while (self.items.count < loopTill) {
[indexPathsToLoad addObject:[NSIndexPath indexPathForItem:self.items.count inSection:0]];
NSLog(#"Added section %d",self.items.count);
AsyncImageView *img = [[DatabaseFetcher alloc] getPostWithID:[NSString stringWithFormat:#"%lu",(unsigned long)self.items.count]
inSection:#"features"
withFrame:CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height)];
[self.items addObject:#[img]];
};
[self.collectionView reloadItemsAtIndexPaths:indexPathsToLoad];
}
#end
Thanks in advance!
Update: I updated the code to use reloadItemsAtIndexPaths and some other improvements base on suggestions. Thanks!
[NSIndexPath indexPathForItem:self.items.count inSection:0]
Should be:
[NSIndexPath indexPathForItem:self.items.count - 1 inSection:0]
update
And you should submit all of your insertions at once by building up an NSMutableArray of index paths in your loop and inserting them at the end (as you've done and commented out). Alternatively, you can put your loop inset of a performBatchUpdates block.
thanks for all the answers.
It looks like I had a miscalculation when trying one of the solutions on the other thread. Here's my new solution that works:
-(void)addNewItems
{
NSLog(#"Loading new items");
NSMutableArray *indexPathsToLoad = [NSMutableArray new];
for (int i = 0; i < LOADING_GAP; i++) {
[indexPathsToLoad addObject:[NSIndexPath indexPathForItem:self.items.count inSection:0]];
[self.items addObject:#"Test"];
}
if (self.items.count == LOADING_GAP) {
[self.collectionView reloadData];
} else {
[self.collectionView insertItemsAtIndexPaths:indexPathsToLoad];
}
}
Thank you!

Resources