I have created a UICollectionView and UICollectionViewCell programmatically without using storyboards, but several things happening and I cannot understand why.
There is a memory leak in BKPhotoCell.
Cells are full screen, but when scrolling the CollectionView, they never reused. Init is called in every indexpath.row.
PrepareForReuse also never called.
Can anyone help me understand what I am doing wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize screenSize = self.view.bounds.size;
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(screenSize.width, screenSize.height)];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[flowLayout setSectionInset:UIEdgeInsetsMake(0, 0, 0, 0)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,0, screenSize.width, screenSize.height) collectionViewLayout:flowLayout];
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView registerClass:[BKPhotoCell class] forCellWithReuseIdentifier:#"BKPhotoCell"];
[self.collectionView setPagingEnabled:YES];
[self.collectionView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self.view addSubview:self.collectionView];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
BKPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"BKPhotoCell" forIndexPath:indexPath];
[cell.imageView setImage:[UIImage imageNamed:[_photos objectAtIndex:indexPath.row]]];
return cell;
}
BKPhotoCell.h:
#interface BKPhotoCell : UICollectionViewCell
#property (nonatomic, strong) UIImageView *imageView;
#end
BKPhotoCell.m:
#interface BKPhotoCell() <UIScrollViewDelegate>
#property (nonatomic ,strong) UIScrollView *scrollView;
#end
#implementation BKPhotoCell
#define isPortrait [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown
#pragma mark - ScrollView Delegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)?
(scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)?
(scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
_imageView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
scrollView.contentSize.height * 0.5 + offsetY);
}
#pragma mark - View Lifecycle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.bounds.size.width, self.contentView.bounds.size.height)];
[self.scrollView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
[self.scrollView setContentMode:UIViewContentModeScaleAspectFit];
[self.scrollView setDelegate:self];
[self.contentView addSubview:_scrollView];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.bounds.size.width, self.contentView.bounds.size.height)];
[self.imageView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self.imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.scrollView addSubview:self.imageView];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
NSLog(#"Prepare for reuse");
}
- (void)layoutSubviews {
[super layoutSubviews];
[self.imageView setFrame:CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height)];
// NSLog(#"Setting Content Size: %f, %f", _imageView.image.size.width, _imageView.image.size.height);
[_scrollView setContentSize:_imageView.image.size];
CGFloat offsetX = (_scrollView.bounds.size.width > _scrollView.contentSize.width)?
(_scrollView.bounds.size.width - _scrollView.contentSize.width) * 0.5 : 0.0;
CGFloat offsetY = (_scrollView.bounds.size.height > _scrollView.contentSize.height)?
(_scrollView.bounds.size.height - _scrollView.contentSize.height) * 0.5 : 0.0;
_imageView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX,
_scrollView.contentSize.height * 0.5 + offsetY);
float minimumZoomScale;
if (isPortrait) {
minimumZoomScale = _imageView.frame.size.width >= _imageView.frame.size.height ? _scrollView.frame.size.width / _imageView.frame.size.width : _scrollView.frame.size.height / _imageView.frame.size.height;
} else {
minimumZoomScale = _imageView.frame.size.width > _imageView.frame.size.height ? _scrollView.frame.size.width / _imageView.frame.size.width : _scrollView.frame.size.height / _imageView.frame.size.height;
}
[self.scrollView setMinimumZoomScale:minimumZoomScale];
[self.scrollView setMaximumZoomScale:minimumZoomScale * 2];
[self.scrollView setZoomScale:minimumZoomScale];
}
If you are using iOS7 it could be you are running into a reuse bug!
I do have the same issue, it works fine on iOS6.1 and iOS6, but as soon as it's started on iOS7 (final) the cells never get reused!
I don't have a fix, I'm trying to create my own reuse logic.
Edit:
I got something working, so you need to save your attributes from the layout (maybe override FlowLayout if you are using it).
Then in
- (void)collectionView:(UICollectionView *)collectionView
didEndDisplayingCell:(UICollectionViewCell *)cell
forItemAtIndexPath:(NSIndexPath *)indexPath
save your cell to a NSMutableArray.
in
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
check your array for cells and apply the properties e.g.:
UICollectionViewCell *cell;
if (![_removedCells count]) {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
} else {
cell = [_removedCells lastObject];
[_removedCells removeLastObject];
[cell prepareForReuse];
UICollectionViewLayoutAttributes* attr = [_layout getTempAttribute:indexPath];
[cell setFrame: attr.frame];
[cell applyLayoutAttributes:attr];
if (![cell superview]) {
[_collectionView addSubview:cell];
}
}
getTempAttribute just retrieves the previously calculated position for my UICollectionViewCell from the UICollectionViewLayout, so just a lookup by indexPath and returns the UICollectionViewLayoutAttributes, it looks as if it's working fine and reusing the UICollectionViewCells - but I can't guarantee anything ;-)
Edit2: After further testing I have to come to the conclusion that this breaks the rotation in the UICollectionView, leading to weird layout issues!
Related
I have a UICollectionView in a custom UITableViewCell, only UIImageView in the UICollectionView. I use SDWebImage to load image.What I want is after loading the image, both UICollectionView and it's contentView(UITableViewCell) update themselves' height to show all the image. For example, if I have three images in UICollectionView, I hope the collectionview's height equals to all three images' height summation.
Here is some code:
TableView:
- (void)createPostDetailUI{
_postDetailTableView = [UITableView new];
_postDetailTableView.delegate = self;
_postDetailTableView.dataSource = self;
_postDetailTableView.estimatedRowHeight = 180;
_postDetailTableView.tableFooterView = [UIView new];
[_postDetailTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
_postDetailTableView.rowHeight = UITableViewAutomaticDimension;
[self makeConstraints];
}
- (void)makeConstraints{
[_postDetailTableView mas_makeConstraints:^(MASConstraintMaker *make) {
UIEdgeInsets padding = UIEdgeInsetsMake(0, 0, 50, 0);
make.edges.equalTo(self.view).insets(padding);
}];
}
- (void)requestPostData{
//some request code
[_commentsArray addObjectsFromArray:[PostCommentModel arrayWithResponseObject:responseObject][0]];
[_postDetailTableView reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _commentsArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
PostDetailHeaderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PostDetailHeaderTableViewCell" forIndexPath:indexPath];
cell = [[PostDetailHeaderTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PostDetailHeaderTableViewCell"];
[cell updateCellWithModel:_postModel];
return cell;
}
UITableViewCell(UICollectionView inside it):
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//some other views
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
layout.minimumLineSpacing = 4.0;
layout.estimatedItemSize = CGSizeMake(300, 300);
_postImageCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
_postImageCollectionView.backgroundColor = [UIColor clearColor];
_postImageCollectionView.showsHorizontalScrollIndicator = NO;
_postImageCollectionView.autoresizesSubviews = YES;
[_postImageCollectionView registerClass:[PostDetailImageCollectionViewCell class] forCellWithReuseIdentifier:#"PostDetailImageCollectionViewCell"];
_postImageCollectionView.delegate = self;
_postImageCollectionView.dataSource = self;
[self.contentView addSubview:_postImageCollectionView];
[self makeConstraints];
}
return self;
}
- (void)makeConstraints{
//some other views' autolayout code
[_postImageCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_postContentLabel);
make.right.equalTo(_postContentLabel);
make.top.equalTo(_postContentLabel.mas_bottom).offset(14);
make.height.greaterThanOrEqualTo(#20);
make.bottom.equalTo(self.contentView).offset(-16);
}];
}
- (void)updateCellWithModel:(PostsModel *)model{
_imageArray = [model getImageList];
[_postImageCollectionView reloadData];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return _imageArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
PostDetailImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"PostDetailImageCollectionViewCell" forIndexPath:indexPath];
NSString *cellImageURL = _imageArray[indexPath.row];
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:cellImageURL] placeholderImage:[UIImage imageNamed:#"icon_default"]];
return cell;
}
UICollectionViewCell:
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
_imageView = [UIImageView new];
_imageView.frame = self.contentView.frame;
_imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.contentView addSubview:_imageView];
}
return self;
}
I use auto layout and use masonry to manage it. But whatever I try to fix it, it just show me 20pt height.
ps:How to make CollectionViewCell frame fit image frame
Try this to calculate height
CGheight height= [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height+2;
add this in ur custom cell and call this from collectionview delegate method
CollectionView horizontal scroll not working in ios 7 but it's working fine in ios 8 and 9. Is there any solution for this ?
The Code is here:
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.itemSize = CGSizeMake(330, 100);
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, 350, 100) collectionViewLayout:layout];
collection.delegate = self;
collection.dataSource = self;
collection.backgroundColor = [UIColor greenColor];
collection.pagingEnabled = YES;
[collection registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:collection];
It now fits my needs, and could be useful for someone else, so here is my code:
I have tested In iOS7-8-9. Below example is for Default iPad. You Just need to change target settings and O.S Version.
https://github.com/philippeauriach/fullyhorizontalcollectionview
Please download it & let us know ur comments. Happy Coding!
If you want to add collection view onto the View then use below code. Below code into i have created CL View programmatically and It's also working correctly with Autolayout and iOS 7-8-9. Please implement below code and let us know ur comments.
.H File
#interface HorizontalCollectionViewController : UIViewController<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>{
NSIndexPath *visibleIndexPath;
}
#property (nonatomic, assign) NSInteger selectedCell;
#property (strong, nonatomic) IBOutlet UICollectionView *horizonCLView;
.M File
#import "HorizontalCollectionViewController.h"
static NSString * const CellIdentifier = #“horizonCell";
#interface HorizontalCollectionViewController ()
#end
#implementation HorizontalCollectionViewController
#synthesize horizonCLView;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"view frame : %#",NSStringFromCGRect(self.view.frame));
[self.view layoutIfNeeded];
[self.view setNeedsLayout];
[self viewDidLayoutSubviews];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = self.view.frame.size;
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[layout setMinimumInteritemSpacing:0.f];
[layout setMinimumLineSpacing:0.f];
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
horizonCLView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
horizonCLView.dataSource = self;
horizonCLView.delegate = self;
horizonCLView.backgroundColor = [UIColor lightGrayColor];
horizonCLView.scrollEnabled = YES;
[horizonCLView setBounces:NO];
[horizonCLView setUserInteractionEnabled:YES];
[horizonCLView setPagingEnabled:YES];
[horizonCLView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellIdentifier];
[self.view addSubview:horizonCLView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewWillAppear:(BOOL)animated{
//Select Current Image For Sare In Social Media
// currentImageIndex = selectedCell;
[horizonCLView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:selectedCell inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
CGRect visibleRect = (CGRect){.origin = self.horizonCLView.contentOffset, .size = self.horizonCLView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
visibleIndexPath = [self.horizonCLView indexPathForItemAtPoint:visiblePoint];
// NSLog(#"visibleIndexPath.row in View will appear %ld",(long)visibleIndexPath.row);
//SelectedCell is a selected image from gallary view
NSLog(#"selectedCell in View will appear: %ld",(long)selectedCell);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [dataAry count];
}
#pragma Here we set the frame of horizontal scrll view
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// expand cell to fill the entire view
return collectionView.frame.size;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
self.title = [[self.dataAry objectAtIndex:indexPath.row] valueForKey:#“dataAryName"];
//imageVI.image = nil;
imageVI = (UIImageView *)[cell.contentView viewWithTag:100];
if (!imageVI){
imageVI = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height)];
imageVI.contentMode = UIViewContentModeScaleAspectFill;
imageVI.tag = 100;
imageVI.clipsToBounds = YES;
[cell.contentView addSubview:imageVI];
}
dispatch_async(dispatch_get_main_queue(), ^{
[asSetLib assetForURL:[NSURL URLWithString:[[self.dataAry objectAtIndex:indexPath.row] valueForKey:#"dataAryName"]] resultBlock:^(ALAsset *asset) {
// imageVI.image = [UIImage imageWithCGImage:asset.defaultRepresentation.fullScreenImage];
imageVI.image = [UIImage imageWithCGImage:asset.defaultRepresentation.fullResolutionImage];
NSLog(#"Preview view into album loaded successfully!");
} failureBlock:^(NSError *error) {
NSLog(#"An error occurred while loading image: %#", error.description);
}];
});
return cell;
}
Sudha, I think this issues in your code not an iOS7 issues.
Here, I have review two bug in ur code.
1)In this line you have give static width of collection view,
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, 350, 100) collectionViewLayout:layout];
Instead Of it will be goes look like,
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, self.view.bounds.size.width, 100) collectionViewLayout:layout];
Make sure your collection view width size always go with according to your view size.
2)Make sure, Your layout item size width higher then collection view width frame. Otherwise Scrolling was not effected.
layout.itemSize = CGSizeMake(self.view.bounds.size.width+10, 100);
3) Carefully use,
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
delegate method of collectionview layout size method.
4)Finally your code look like,
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(self.view.bounds.size.width+10, 100);
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, self.view.bounds.size.width, 100) collectionViewLayout:layout];
collection.delegate = self;
collection.dataSource = self;
collection.backgroundColor = [UIColor greenColor];
collection.pagingEnabled = YES;
collection.scrollEnabled = YES;
collection.userInteractionEnabled = YES;
[collection registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:collection];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 1;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
return cell;
}
Happy Coding!
I've used a line of code after adding collectionView on view that its working fine in ios 7 also.
add this code after [self addSubview:self.collectionView];
here the code:
[self performSelector:#selector(update) withObject:nil afterDelay:1];
(void)update {
[self.collectionView setContentOffset:CGPointMake(1, 0)];
}
I need to be able to load images properly in both the landscape and portrait mode and for all devices.
Also I need a proper memory management while loading the images. right now my code loads all the images at once but in future I will add more images so need an optimized memory solution.
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
self.navigationController.navigationBarHidden = YES;
_photoArray = [NSArray arrayWithObjects:#"image1.jpg",#"image2.jpg",#"image3.jpg",#"image4.jpg",#"image5.jpg",#"image6.jpg",#"image7.jpg",#"image8.jpg",#"image9.jpg", nil];
self.pageControl.numberOfPages = _photoArray.count;
CGSize screen = [[UIScreen mainScreen] bounds].size;
for(int i = 0; i < _photoArray.count; i++)
{
self.subScrollView = [[UIScrollView alloc] init];
self.subScrollView.frame = CGRectMake((i * screen.width), 0, screen.width, screen.height);
[self.subScrollView setMinimumZoomScale:1];
[self.subScrollView setZoomScale:1];
[self.subScrollView setMaximumZoomScale:3];
self.subScrollView.delegate = self;
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:_photoArray[i]]];
imgView.frame = self.subScrollView.bounds;
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
imgView.tag = i;
[self.subScrollView addSubview:imgView];
[_scrView addSubview:self.subScrollView];
if(i == _photoArray.count-1)
_scrView.contentSize = CGSizeMake(self.subScrollView.frame.origin.x + self.subScrollView.frame.size.width, screen.height);
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [scrollView viewWithTag:self.pageControl.currentPage];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//page control
CGFloat pageWidth = self.scrView.frame.size.width;
self.pageControl.currentPage = (self.scrView.contentOffset.x +pageWidth/2)/pageWidth;
}
I think that the best option to optimize the memory is use a UICollectionView instead UIScrollView. Also you can use UIPageControl with UICollectionView.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.imagesArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell == [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",indexPath.row]]];
[cell.addSubView:image];
return cell;
}
I have a UICollectionView that is using the Flow Layout. At this point I'm not really doing anything special. I'm just programmatically adding the view and the UICollectionViewCell.
When you touch a cell it is registering the touch event for the cell that is located above it. So if you touch a cell on row 2 the the cell above is the one that actually registers the touch.
Here is the code that I have setting things up.
#interface KFYSearch() <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UISearchBarDelegate>
#property(nonatomic, strong)UISearchBar *searchBar;
#property(nonatomic, strong)UICollectionView *collectionView;
#property(nonatomic, strong)NSArray *collectionData;
#end
#implementation KFYSearch
-(id)initWithView:(UIView*)view
{
self = [super init];
if(self)
self.view = view;
return self;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(_searchBar == nil)
{
self.view.frame = CGRectMake(20, 20, self.view.superview.frame.size.width - 40, self.view.superview.frame.size.height - 40);
[self.view setBackgroundColor:[UIColor whiteColor]];
[self createChildViews];
}
}
-(void)createChildViews
{
_searchBar = [[UISearchBar alloc] initWithFrame: CGRectMake(5, 5, self.view.frame.size.width - 10, 30)];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(_searchBar.frame.origin.x, _searchBar.frame.origin.y + (_searchBar.frame.size.height + 2), _searchBar.frame.size.width, self.view.frame.size.height - ((_searchBar.frame.origin.y + _searchBar.frame.size.height) + 10)) collectionViewLayout:flowLayout];
_collectionView.dataSource = self;
_collectionView.delegate = self;
[_collectionView registerClass:[KFYKlickableCell class] forCellWithReuseIdentifier:#"Cell"];
[_collectionView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:_searchBar];
[self.view addSubview:_collectionView];
[self getData];
}
-(void)getData
{
KFYGetKlickablesAction *getKlickablesAction = [[KFYGetKlickablesAction alloc]init];
_collectionData = [getKlickablesAction mockData];
[_collectionView reloadData];
}
#pragma UICollectionView Delegate stuff;
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _collectionData.count;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
KFYKlickableCell *cell= [_collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
[cell setBackgroundColor:[UIColor redColor]];
KFYKlickableVO *vo = [_collectionData objectAtIndex:indexPath.row];
[cell renderKlickable:vo];
return (UICollectionViewCell*)cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(60, 60);
}
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(5, 5, 5, 5);
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
KFYKlickableVO *vo = [_collectionData objectAtIndex:indexPath.row];
NSLog(vo.tag);
}
#pragma UITextField Delegate stuff
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
self.view.frame = CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
self.view.frame.size.height - 215 + 50); //resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
//keyboard will hide
self.view.frame = CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
self.view.frame.size.height + 215 - 50); //resize
}
#end
Hi friends is it possible to add a cover flow effect in uicollection view in horizontal layout.if possible means kindly tell me how to implement the effect.
Yes it is possible, You need to Implement your custom UICollectionViewFlowLayout.
Make a custom class which inherits UICollectionViewFlowLayout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES; }
- (UICollectionViewScrollDirection)scrollDirection {
return UICollectionViewScrollDirectionVertical; }
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
UICollectionView *collectionView = [self collectionView];
UIEdgeInsets insets = [collectionView contentInset];
CGPoint offset = [collectionView contentOffset];
CGFloat minY = -insets.top;
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
// minY is Point where we implement this cover flow.
if (offset.y < minY) {
// Figure out how much we've pulled down
CGFloat deltaY = fabsf(offset.y - minY);
for (UICollectionViewLayoutAttributes *attrs in attributes) {
// Locate the header attributes
NSString *kind = [attrs representedElementKind];
if (kind == UICollectionElementKindSectionHeader) {
// This is header's height and y based on how much the user has scrolled down.
CGSize headerSize = [self headerReferenceSize];
CGRect headerRect = [attrs frame];
headerRect.size.height = MAX(minY, headerSize.height + deltaY);
headerRect.origin.y = headerRect.origin.y - deltaY;
[attrs setFrame:headerRect];
break;
}
}
}
return attributes; }
Now in your class where you allocate UICollectionView
CustomCoverFlowHeaderCollectionViewLayout *flow; flow = [[CustomCoverFlowHeaderCollectionViewLayout alloc] init]; [stretchyLayout setHeaderReferenceSize:CGSizeMake(320.0, 160.0)]; // Set our custom layout [collectionView setCollectionViewLayout: flow]; [collectionView setAlwaysBounceVertical:YES]; [collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:#"myCoverCollectionView"];
You are almost done
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
if (!header) {
header = [collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:#"myCoverCollectionView" forIndexPath:indexPath];
CGRect bounds;
bounds = [header bounds];
UIImageView *imageView;
imageView = [[UIImageView alloc] initWithFrame:bounds];
[imageView setImage:[UIImage imageNamed:#"background"]];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[imageView setClipsToBounds:YES];
[imageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[header addSubview:imageView];
}
return header; }
Here is a good project based on UICollectionView for you.