I am trying to simply add a UIView to a UICollectionViewCell that takes up the entire cell's frame. The code I have now only displays a single cell in the top left corner (I suspect each cell is getting layer out on top of each other). How exactly can I do this?
I plan on subclassing UIView later so as to customize the view that I am adding to the cell. I don't want to subclass UICollectionViewCell however based on the way I will be using it.
#pragma mark - Collection view data source
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 6;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UIView *menuItem = [[UIView alloc] init];
menuItem.frame = cell.frame;
menuItem.backgroundColor = [UIColor greenColor];
[cell addSubview:menuItem];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; {
return CGSizeMake(60, 60);
}
You'll need to use bounds, not frame. If you don't know the difference between the two or why this matters, you should read up on this and get comfortable with it before going further:
menuItem.frame = cell.bounds;
You'll also want to set an autoresizing mask, since the cell won't initially be at the correct size:
menuItem.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
And, really, you should be adding this to the cell's contentView property:
[cell.contentView addSubview:menuItem];
menuItem.frame = cell.contentView.bounds;
That said, if you plan on adding lots of subviews to menuItem, I recommend subclassing UICollectionViewCell instead of trying to build it in your cellForItemAtIndexPath: method. It will be much easier to control if the layout and setup is encapsulated in a different class, and you can respond to height / width changes by overriding layoutSubviews.
You should only interact with the cell's contentView in this case.
UIView *menuItem = [UIView new];
menuItem.frame = cell.contentView.bounds;
menuItem.backgroundColor = [UIColor greenColor];
[cell.contentView addSubview:menuItem];
It's Swift version.
let menuItem = UIView.init()
menuItem.frame = cell.bounds
menuItem.backgroundColor = .green
cell.contentView.addSubview(menuItem)
menuItem.frame = cell.contentView.bounds
Swift 5 Apple doc:
var contentView: UIView
The main view to which you add your cell’s custom content.
When configuring a cell, you add any custom views representing your cell’s content to this view. The cell object places the content in
this view in front of any background views.
var backgroundView: UIView?
The view that is displayed behind the cell’s other content.
Use this property to assign a custom background view to the cell. The background view is placed behind the content view and its frame
is automatically adjusted so that it fills the bounds of the cell.
Example:
let template = UIView()
self.backgroundView = template
template.layer.cornerRadius = 10
template.backgroundColor = .white
Related
Follow this answer on SO I be able to create UICollectionView programmatically. But I can't find any better solution when I try to add subview into UICollectionViewCell. Here is how most answer on SO achieve
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)];
image.image = /*some image*/
[cell addSubview:image];
return cell;
}
Maybe i'm wrong but the purpose of using UICollectionView wasn't because of recycle and reuse to optimize the performance? If using the code above when the user scrolling wasn't it add more and more UIImageView into UICollectionViewCell subview when dequeueReusableCellWithReuseIdentifier get trigger?
So what is the better way to do this? I can't use UITableView for this because I need the horizontal scrolling technique.
NOTE: I need to create it programmatically without using xib.
Yes, It will add imageView everytime when your collection view will get scrolled! And it is not good approach. Now, what you can do is, Take one image view in your collectionview cell, I mean in interface builder(xib or storyboard whatever you have used) and in cellForItemAtIndexPath just show or hide that image view as per need or change image of it as per requirement!
Update :
If you have create collection view programmatically then you can set some flag in your cellForItemAtIndexPath! Take one flag and set it after adding imageview. and you can declare imageview and flag as global variable. Something like,
if (!isImageAdded) {
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)];
imageView.image = /*some image*/
[cell addSubview:image];
isImageAdded = YES;
}
else{
imageView.image = /*some image*/
}
I added a view to collectionView cell on selection and reloaded item but the view is not visible on first selection ,its visible only on clicking cell again.After the first load of collectionView,on first selection of collectionView cell ,view added is being added but is not visible, the size is increased,only view is visible after second selection.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
selectedIndexPath = indexPath;
PastPicksGameCollectionViewCell *cell = (PastPicksGameCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(50,122, 150, 120)];
[view setBackgroundColor:[UIColor blueColor]];
[cell.contentView addSubview:view]
[pastPicksGameCollectionView reloadItemsAtIndexPaths:#[selectedIndexPath]];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:selectedIndexPath]) {
return CGSizeMake(320, 200);
}
return CGSizeMake(300, 120);
}
I think reloadItemsAtIndexPaths: is working against you: it causes the collectionView to discard the cell associated with that item (i.e. the cell you have just added the subview to) and to load from the queue a new cell (which doesn't have the subview) for that item. The discarded cell is placed on the queue for re-use. When you click again, the same thing happens. But this time, the originally discarded cell (which does have the subView) is re-used, hence being displayed.
Personally, I would avoid adding subviews to cells like this - I would add a "permanent" UIView property to your custom cell class which you can then use in didSelectItemAtIndexPath. But you must ensure in cellForItemAtIndexPath that you reset it (e.g. with if (indexPath isEqual:selectedIndexPath) { create/show the subview } else { hide the subview/set to nil) }.
MY OBJECTIVE: I need to load an image on the UICollectionView, but changing the Y position of it on the UIImageView frame, because the loaded image is taller than the cell display window, and I need to display a specific part of it.
SETTINGS: The UICollectionView and the UIImageView were manually added to the storyboard (not programmatically). The UIImageView view mode is set to Aspect Fill on the Attributes Inspector.
THE PROBLEM: I've tried changing the UIImageView frame after (and also before) loading the image, but the change only takes effect after the UICollectionView is scrolled up and down, and I need the image position updated when it first loads.
PS: I've also tried all the different types of view mode on the UIImageView, but it doesn't seem to make any difference.
Here's the coding I'm using for it:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCell *cell = (PhotoCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"PhotoCell" forIndexPath:indexPath];
cell.photoImageView.image = [UIImage imageNamed:_stringImageURL];
CGRect oldFrame = cell.photoImageView.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, -45, oldFrame.size.width, oldFrame.size.height);
cell.photoImageView.frame = newFrame;
cell.backgroundColor = [UIColor redColor];
return cell;
}
Any help would be greatly appreciated! Thanks in advance!
I have a UICollectionView which contains custom UICollectionViewCell. The collection view has a background image.
I would show the background image, but the collection view (or its cells) has always a white background which prevents my background image to show.
Here is the code:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
AgendaCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:agendaCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.layer.borderWidth=0.0f;
cell.layer.backgroundColor = [UIColor clearColor].CGColor;
cell.contentView.layer.backgroundColor = [UIColor blackColor].CGColor;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
[cell setCurrentDateAtIndex:([indexPath row]) date:currentMonth events:events];
return cell;
}
The AgendaCollectionCell is very simple: I did a cell by using IB and set all background images to clearColor. Also the collection view use a very basic custom layout.
An excertp of what is shown in the pic:
The collection view show cells with numbers. Beneath the collection view there is a background which is not shown because of the white color of the cells.
Any hint appreciated. Thank you.
SOLVED.
The problem was in the rendering of the custom cell. I used a method (a lost method...) which set the background color of the cell. For non custom cell, the code in my question is correct.
you can also background color for your custom UICollectionView by setting backgroundview for UICollectionView.
UIView *blueView = [[UIView alloc]init];
blueView.backgroundColor = [UIColor blueColor];
self.collectionView.backgroundView = blueView;
I have been doing much reading and looking at app samples and am still unsure how to implement a collection view that pushes to a detail view with paging?
I am able to get a collection view to push to a static detail view (unfortunately without titles) and I can get paging working without a collection view but not both together!? I also need to take across a title as well which is an important part.
Please can someone help me with this as I may go insane soon :)
Many thanks in advance!
Just push another collection view controller with flow layout, horizontal scrolling direction, enabled paging property and set itemSize property of your layout to be full screen. Before pushing set content offset of this controller to be on a selected image. Try the following code. You should call initWithCollectionViewLayout to initialize your collection view.
-(id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout {
if (self = [super initWithCollectionViewLayout:layout]) {
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
layout.itemSize = self.collectionView.bounds.size;
layout.minimumLineSpacing = 0;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.collectionView.pagingEnabled = YES;
// In order to see cells you can declare something like colors array in .h
self.colors = #[[UIColor redColor], [UIColor greenColor], [UIColor blueColor]];
}
return self;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.shopNames.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
[cell.contentView setBackgroundColor:self.colors[indexPath.item]];
return cell;
}
P.S. To set content offset use [self.collectionView setContentOffset:CGPointMake(40, 0)];