Nested UIView inside UICollectionViewCell not updating - ios

I'm trying to display a list of recepcies for at pet proyect, which I've modeled with a UICollectionView and for each item, a custom UICollectionViewCell.
This UICollectionViewCell has inside a UIImageView and a custom UIView for layout pruposes.
The tree goes like this
HomeViewController (UIViewController)
└── UICollectionView
└── RecepieCardCollectionViewCell (UICollectionViewCell)
├── UIImageView
└── RecepieCardInfoView (UIView)
└── UILabel
I'm comforming to the UICollectionViewDelegate and UICollectionViewDataSource protocols at the HomeViewController, and then I'm configuring the cells and their nested UIViews though a configure method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: RecepieCardCollectionViewCell.identifier, for: indexPath
) as? RecepieCardCollectionViewCell else {
return UICollectionViewCell()
}
cell.configure(self.recepies[indexPath.row])
return cell
}
Then, at the RecepieCardCollectionViewCell:
func configure(_ recepie: Recepie) {
cardInfoView.configure(recepie)
thumbnail.kf.setImage(with: URL(string: recepie.getCover()))
}
And, finally, at the RecepieCardInfoView
func configure(_ recepie: Recepie) {
label.text = recepie.getName()
}
The thing is that the most deep nested UILabel at the RecepieCardInfoView, is receiving the data, but is not being updated. It always shows the same placeholder text, instead of the actual recepie name.
Things I've tried:
Placing .setNeedsDisplay() to all the element, with no results.
Using DispatchQueue.main.async but didn't work, which makes sense since I'm not using an API request to show the recepies (for now).
Move the label inside RecepieCardInfoView to the RecepieCardCollectionViewCell. This worked for some reason, but I would like to understand why.
If you need more context of the code, you can find the full repository here at the branch feat/recepies-list
I've been asked to add the full code of the cell, here it is:
import UIKit
import Kingfisher
class RecepieCardCollectionViewCell: UICollectionViewCell {
static let identifier = "RecepieCardUICollectionViewCell"
let thumbnail: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.kf.setImage(with: URL(string: "https://i.imgur.com/ISxVZHA.png"))
return image
}()
let content: UIView = {
let view = UIView(frame: .zero)
view.clipsToBounds = true
view.layer.cornerRadius = 40
return view
}()
let cardInfoView = RecepieCardInfoView(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .themeWhite
layer.cornerRadius = 40
addSubview(content)
content.frame = bounds
content.addSubview(thumbnail)
let cardInfoView = RecepieCardInfoView(frame: .zero)
content.addSubview(cardInfoView)
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.17
layer.shadowOffset = .zero
layer.shadowRadius = 10
NSLayoutConstraint.activate([
thumbnail.leadingAnchor.constraint(equalTo: content.leadingAnchor),
thumbnail.trailingAnchor.constraint(equalTo: content.trailingAnchor),
thumbnail.topAnchor.constraint(equalTo: content.topAnchor),
thumbnail.heightAnchor.constraint(equalTo: thumbnail.widthAnchor),
cardInfoView.topAnchor.constraint(equalTo: content.bottomAnchor, constant: -100),
cardInfoView.bottomAnchor.constraint(equalTo: content.bottomAnchor),
cardInfoView.leadingAnchor.constraint(equalTo: content.leadingAnchor),
cardInfoView.trailingAnchor.constraint(equalTo: content.trailingAnchor),
])
}
required init(coder: NSCoder) {
fatalError()
}
func configure(_ recepie: Recepie) {
cardInfoView.configure(recepie)
thumbnail.kf.setImage(with: URL(string: recepie.getCover()))
}
}
Thanks you in advance!

You create 2 instances of cardInfoView inside RecepieCardCollectionViewCell
let cardInfoView = RecepieCardInfoView(frame: .zero) // here 1
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .themeWhite
layer.cornerRadius = 40
addSubview(content)
content.frame = bounds
content.addSubview(thumbnail)
let cardInfoView = RecepieCardInfoView(frame: .zero) // and here 2
The problem is that you add the inner view without updating it's content , and update the outer view without adding it to cell hierarchy

Related

Swift custom UICollectionViewCell subViews disappear when imageView image set at ViewController

I faced weird issue while handling UICollectionView
I Created simple custom UICollectionViewCell, which has only one imageView and Label:
There's default placeholder image for Cell's imageView and updating imageView.image from collectionView(_:cellForItemAt:). But When image is set, all subview of cell disappears:
(Cells are not disappear at same time because downloading & setting image is async)
Note: Sample data I used is not wrong (Same data works for TableView in same app)
Why this happens and how can I fix it?
this is Sample data I used:
let movies = [
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955)
]
this is my part of ViewController:
lazy var collectionView = { () -> UICollectionView in
// FlowLayout
var flowLayout = UICollectionViewFlowLayout()
flowLayout.headerReferenceSize = CGSize(width: self.preferredContentSize.width, height: 180)
flowLayout.sectionInset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
flowLayout.minimumInteritemSpacing = 20
flowLayout.minimumLineSpacing = 20
// Collection View
var collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout)
collectionView.register(DiscoverCollectionViewCell.self, forCellWithReuseIdentifier: identifiers.discover_collection_cell)
collectionView.register(DiscoverCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: identifiers.discover_collection_header)
collectionView.backgroundColor = UIColor(named: Colors.background)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Discover"
collectionView.dataSource = self
collectionView.delegate = self
self.view.backgroundColor = UIColor(named: Colors.background)
self.view.addSubview(collectionView)
collectionView.snp.makeConstraints { $0.edges.equalTo(self.view.safeAreaLayoutGuide) }
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Sample Cell
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifiers.discover_collection_cell, for: indexPath) as? DiscoverCollectionViewCell else { return DiscoverCollectionViewCell() }
let movie = movies[indexPath.row]
cell.movieTitle.text = movie.title
DispatchQueue.global().async {
guard let imageURL = URL(string: "https://image.tmdb.org/t/p/original/\(movie.posterPath)") else { return }
guard let imageData = try? Data(contentsOf: imageURL) else { return }
DispatchQueue.main.sync {
cell.posterImage.image = UIImage(data: imageData)
}
}
return cell
}
and this is my custom CollectionViewCell, I used Snapkit, Then library:
class DiscoverCollectionViewCell: UICollectionViewCell {
//MARK: Create properties
lazy var posterImage = UIImageView().then {
$0.image = UIImage(named: "img_placeholder")
$0.contentMode = .scaleAspectFit
}
lazy var movieTitle = UILabel().then {
$0.font = UIFont.systemFont(ofSize: 15)
$0.textColor = .white
$0.numberOfLines = 2
$0.minimumScaleFactor = 10
}
override init(frame: CGRect) {
super.init(frame: frame)
// add to view
self.addSubview(posterImage)
self.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
}
movieTitle.snp.makeConstraints { make in
make.top.equalTo(posterImage.snp.bottom).offset(5)
make.bottom.greaterThanOrEqualToSuperview()
make.leading.equalTo(posterImage.snp.leading)
make.trailing.equalTo(posterImage.snp.trailing)
}
self.backgroundColor = .blue
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Two issues with your cell's layout...
// add to view
self.addSubview(posterImage)
self.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
}
You should always add UI elements to the cell's .contentView, not to the cell itself.
You did not constrain the bottom of the image view.
// add to ContentView!
self.contentView.addSubview(posterImage)
self.contentView.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.bottom.equalToSuperview()
}
Edit
You were missing a couple things from your post (including how you're setting your cell / item size), so while the above changes do fix the image not showing at all, it's not quite what you're going for.
I'm assuming you're setting the flow layout .itemSize somewhere, so your original constraints - without adding .bottom. to the image view constraints - were close...
When you add an image to a UIImageView, the intrinsicContentSize becomes the size of the image. Your constraints are controlling the width, but...
This constraint on your label:
make.bottom.greaterThanOrEqualToSuperview()
means "put the Bottom of the label at the Bottom of its superview or farther down!"
When your image loads, it sets the image view Height to its own Height and pushes the label way down past the bottom of the cell.
That line needs to be:
make.bottom.equalToSuperview()
That will prevent the Bottom of the label from moving.
Next, you need to tell auto-layout "don't compress or stretch the label vertically":
// prevent label from stretching vertically
movieTitle.setContentHuggingPriority(.required, for: .vertical)
// prevent label from compressing vertically
movieTitle.setContentCompressionResistancePriority(.required, for: .vertical)
Without that, the label will be compressed down to Zero height.
I find it very helpful to add comments so I know what I'm expecting to happen:
override init(frame: CGRect) {
super.init(frame: frame)
// add to ContentView
self.contentView.addSubview(posterImage)
self.contentView.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
// constrain image view to
// Top / Left / Right of contentView
make.top.left.right.equalToSuperview()
}
// prevent label from stretching vertically
movieTitle.setContentHuggingPriority(.required, for: .vertical)
// prevent label from compressing vertically
movieTitle.setContentCompressionResistancePriority(.required, for: .vertical)
movieTitle.snp.makeConstraints { make in
// constrain Top of label to Bottom of image view
// because we've set Hugging and Compression Resistance on the label,
// this will "pull down" the bottom of the image view
make.top.equalTo(posterImage.snp.bottom).offset(5)
// constrain Bottom of label to Bottom of contentView
// must be EQUAL TO
//make.bottom.greaterThanOrEqualToSuperview()
make.bottom.equalToSuperview()
// Leading / Trailing equal to image view
make.leading.equalTo(posterImage.snp.leading)
make.trailing.equalTo(posterImage.snp.trailing)
}
self.backgroundColor = .blue
}
Now we get this result:
and after the images download:
One final thing - although you may have already done something to address this...
As you see in those screenshots, setting .numberOfLines = 2 on a label does not force a 2-line height... it only limits it to 2 lines. If a Movie Title is short, the label height will be shorter as seen in the 2nd cell.
One way to fix that would be to constrain the label height to something like 2.5 lines by adding this to your init:
if let font = movieTitle.font {
movieTitle.snp.makeConstraints { make in
make.height.equalTo(font.lineHeight * 2.5)
}
}
That will give this output:
Although I am not sure, Because collection view cells are being reused the init of cells only gets called at the first time, not the time when image data is getting loaded from the server.
Try moving your layout-related code(specifically adding subviews and constraining them) in a different method of the cell and call it every time image gets loaded.

UIScrollView inside another view not scrolling

So I've seen other SO questions but I can't really figure out mine
I know my UIScrollView code works because I tested it in a regular UIViewController so I don't think contentSize is the problem, but when I place the same code inside a UICollectionReusableView it doesn't scroll anymore
-Working in UIViewController
override func viewDidLoad() {
super.viewDidLoad()
let scrollingView = colorButtonsView(buttonSize: CGSize(width:100.0,height:50.0), buttonCount: 10)
let scrollView = UIScrollView(frame: UIScreen.main.bounds)
scrollView.backgroundColor = UIColor.black
scrollView.contentSize = scrollingView.frame.size
scrollView.showsHorizontalScrollIndicator = true
self.view.addSubview(scrollView)
scrollView.addSubview(scrollingView)
}
-Not working in UICollectionReusableView
override init(frame: CGRect) {
super.init(frame: frame)
//Add category scroll view
let scrollingView = colorButtonsView(buttonSize: CGSize(width:100.0,height:50.0), buttonCount: 10)
let scrollView = UIScrollView(frame: UIScreen.main.bounds)
scrollView.backgroundColor = UIColor.black
scrollView.contentSize = scrollingView.frame.size
scrollView.showsHorizontalScrollIndicator = true
self.addSubview(scrollView) //Only changes self.view to self
scrollView.addSubview(scrollingView)
}
Better late than never...I had the same problem, so maybe this is why;
I wanted to put a UIScrollView inside a UICollectionReusableView but by accident I had created my custom class as;
class CustomCellHeader: UICollectionViewCell {
}
instead of;
class CustomCellHeader: UICollectionReusableView {
}
Once I changed that, the UIScrollView within my header cell came to life!

Set rounded corners on UIimage in UICollectionViewCell in swift

I have a simple problem that I cannot find a solution to on google, the docs or here.
I have a Collectionview in my view controller. I have created a custom cell, DescriptionCell, that contains a UIImage. I want this image to have rounded corners. However, I don't know where to set the cornerradius on the UIImage layer. I have tried in the cells' awakeFromNib method, in the delegate method CellForRowAtIndexPath and overriden LayoutSubview in the cell but it does not work.
Where should I put the code to set the radius for the UIImage?
To specify, I know how to create rounded corners of a UIImage. But if it is a subview of a Collectionview cell, I do not know where to set the cornerradius.
Here is code for my descriptionCell
class DescriptionCell: UICollectionViewCell {
#IBOutlet weak var mImage: UIImageView!
override func awakeFromNib() {
//mImage.layer.cornerradius = 5
//Does not work, the image is still square in the cell
}
And in the cellforRowAtIndePath
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("descriptioncell", forIndexPath: indexPath) as! DescriptionCell
//cell.mImage.layer.cornerradius = 5
//Does not work, the image is still square in the cell
return cell
}
Thanks in advance!
Well you're using part of the code from the answer you said you were using.
the other part is imageView.clipsToBounds = true
Update your awakeFromNib like this:
override func awakeFromNib() {
mImage.layer.cornerRadius = 5
mimage.clipsToBounds = true
}
To make it a circle you need to set cornerRadius to half of the square height. In your cellForItemAtIndexPath add these lines:
cell.layoutIfNeeded()
cell.mImage.layer.cornerRadius = cell.mImage.frame.height/2
Update
To avoid layoutSubviews from being called twice, override layoutSubviews in your DescriptionCell class and put the code there:
override func layoutSubviews() {
super.layoutSubviews()
layoutIfNeeded()
mImage.layer.cornerRadius = mImage.frame.height/2
}
Have you tried placing it inside the custom UICollectionViewCell's init function?
override init(frame: CGRect) {
super.init(frame: frame)
image.layer.masksToBounds = true
image.layer.cornerRadius = 10
}
You can also create an extension like:
extension UIView {
func addBorder(color: UIColor, cornerRadius: CGFloat = 10, borderWidth: CGFloat = 1.0) {
layer.borderWidth = borderWidth;
layer.borderColor = color.cgColor
layer.cornerRadius = cornerRadius
layer.masksToBounds = true
}
}

How to use rbcollectionviewinfofolderlayout with custom UICollectionViewCell & CollectionViewLayout

What I want to do is display a UICollectionView inside a UICollectionViewCell when this cell is selected. I want to use rbcollectionviewinfofolderlayout to fold out my collection view and show a new collection view inside of this. However I'm not sure how I can implement this into my existing code. I have three collection views inside one view. I hide and unhide my views accordingly to what selection the user makes. I use a custom cell xib for the cells inside my collection views and I have a custom collectionviewflowlayout that makes sure there are always 3 cells showing in the width of the device.
This is what my view controller looks like.
in my viewDidLoad I have to set the RBCollectionViewInfoFolderLayout to my collectionview. As you can see the layout variable holds my CustomCollectionViewFlow which I set as the collection view layout before I implemented the RBCollectionviewinfofolderlayout.
override func viewDidLoad() {
super.viewDidLoad()
musicLib.loadLibrary()
PlaylistCollectionView.indicatorStyle = UIScrollViewIndicatorStyle.White
AlbumCollectionView.indicatorStyle = UIScrollViewIndicatorStyle.White
ArtistCollectionView.indicatorStyle = UIScrollViewIndicatorStyle.White
layout = CustomCollectionViewFlow()
cview = ArtistCollectionView
let lay: RBCollectionViewInfoFolderLayout = ArtistCollectionView.collectionViewLayout as! RBCollectionViewInfoFolderLayout
lay.cellSize = CGSizeMake(80, 80)
lay.interItemSpacingY = 10
lay.interItemSpacingX = 0
let nib = UINib(nibName: "CollectionViewCell", bundle: nil)
cview.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind: RBCollectionViewInfoFolderHeaderKind, withReuseIdentifier: "header")
cview.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind: RBCollectionViewInfoFolderFooterKind, withReuseIdentifier: "footer")
cview.registerClass(collectionViewFolder.self, forSupplementaryViewOfKind: RBCollectionViewInfoFolderFolderKind, withReuseIdentifier: "folder")
cview.registerClass(RBCollectionViewInfoFolderDimple.self, forSupplementaryViewOfKind: RBCollectionViewInfoFolderDimpleKind, withReuseIdentifier: "dimple")
ArtistCollectionView.collectionViewLayout = lay
ArtistCollectionView.registerNib(nib, forCellWithReuseIdentifier: "item")
ArtistCollectionView.dataSource = self
ArtistCollectionView.delegate = self
PlaylistCollectionView.collectionViewLayout = layout
PlaylistCollectionView.registerNib(nib, forCellWithReuseIdentifier: "item")
PlaylistCollectionView.dataSource = self
AlbumCollectionView.collectionViewLayout = layout
AlbumCollectionView.registerNib(nib, forCellWithReuseIdentifier: "item")
AlbumCollectionView.dataSource = self
}
My CustomCollectionViewFlow looks like this
class CustomCollectionViewFlow: UICollectionViewFlowLayout{
override init(){
super.init()
setupLayout()
}
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
setupLayout()
}
override var itemSize: CGSize {
set {
}
get {
let numberOfColumns: CGFloat = 3
let itemWidth = (CGRectGetWidth(self.collectionView!.frame) - (numberOfColumns - 1)) / numberOfColumns
return CGSizeMake(itemWidth, itemWidth)
}
}
func setupLayout() {
minimumInteritemSpacing = 0
minimumLineSpacing = 0
scrollDirection = .Vertical
}
}
I will hold of on putting all my coding here as it will be become to big of a post and the other methodes are kind of irrelevant at this point. However what I did do is put the example application that I made for this on git here for anyone who wants to check it out.
This image shows what the state of my collectionview was before I implemented the rbcollectionview. The second image shows what I'm trying to achieve
This is how the view should look when an item is being tapped
EDIT
I have been able to get it working kind of. I was able to show the layout like I desired. Just like I had it before I implemented the rbcollectionviewinfofolderlayout. However it seems that when the folder is bigger then the screen size it won't actually fold out. It will fold out for a second and collapse again. It might be caused by the layout i've implemented. Below is the code that is responsible for this.
the class that is responsible for my layout
class RBCollectionLayout: RBCollectionViewInfoFolderLayout
{
var view: UIView!
init(view: UIView){
super.init()
self.view = view
setupLayout()
}
override init(){
super.init()
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
func setupLayout(){
let numberofItems: CGFloat = 3
let itemWidth = (CGRectGetWidth(view.frame)) / numberofItems
cellSize = CGSizeMake(itemWidth, itemWidth)
interItemSpacingX = 0
interItemSpacingY = 0
}
}
The method that will calculate the desired with when the screen is changed from portrait to landscape
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if(view_artist.hidden == false){
guard let ArtistFlowLayout = ArtistCollectionView.collectionViewLayout as? RBCollectionViewInfoFolderLayout else {
return
}
lay = RBCollectionLayout(view: self.view)
ArtistCollectionView.collectionViewLayout = lay
ArtistFlowLayout.invalidateLayout()
}
}
this is how the layout is being set in my viewdidload
lay = RBCollectionLayout(view: self.view)
ArtistCollectionView.collectionViewLayout = lay
again all my code is available on my git here
Well, I'm probably the only person who can answer your question, since I wrote this control and I doubt anyone else is actually using it.
You seem to be missing a key component which is the delegate method collectionView:viewForSupplementaryElementOfKind:atIndexPath: where you tell the CollectionView what views to use for the various elements. If you go to the GitHub Repo and look at the example you will see that in that method I return 4 different views depending on the viewKind that was asked for. In your code I believe what you want to do is return your custom flow layout based collection view for the RBCollectionViewInfoFolderFolderKind. This would place your 3 cell flow layout view into the expanded folder of the selected cell.
I cloned your repo but it doesn't appear to be up to date with the code you are showing here.

How to determine the "z-index of a shadow"

I'm sorry for the title, can not synthesize differently the issue. Here's the problem:
In my UICollectionView have some cells that want to put a shadow, they are arranged very close to each other which makes the shadow of each one reach the neighbor (first image), when what I want, is that it only reaches the background (second image).
What I've thought or tried:
I can not put a view behind the cells, adding their frames to it, and apply shadow in this view because the cells has dynamic movement (UIDynamics CollectionView Layout).
I tried, in the subclass of UICollectionViewLayout, put all these cells in the same z-index. Did not work. Find out why:
var zIndex: Int
(...) Items with the same value have an undetermined
order.
I would like some help with my problem, please. Thanks!
From the TheEye response, I decided to implement UIDecorationViews. All great now.
// MARK: At UICollectionViewCustomLayout:
public override init() {
super.init()
// Register the NIB of the view that will hold the shadows:
let nib = UINib(nibName: "Shadow", bundle: nil)
self.registerNib(nib, forDecorationViewOfKind: "shadow")
}
public override func layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
let layoutAtt: UICollectionViewLayoutAttributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: "shadow", withIndexPath: indexPath)
layoutAtt.frame = (layoutAttributesForItemAtIndexPath(indexPath)?.frame)!
layoutAtt.zIndex = -1
return layoutAtt
}
public override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var atts = [UICollectionViewLayoutAttributes]()
let numberOfItems:Int = (self.collectionView?.numberOfItemsInSection(0))!
for index in 0..<numberOfItems {
let layoutItem = layoutAttributesForItemAtIndexPath(NSIndexPath(forItem: index, inSection: 0))!
let frameItem = layoutItem.frame
if CGRectIntersectsRect(frameItem, rect) {
atts.append(layoutAttributesForDecorationViewOfKind("shadow", atIndexPath: NSIndexPath(forItem: index, inSection: 0))!)
atts.append(layoutItem)
}
}
return atts
}
// MARK: At the Nib Class File:
// Here I created a additional view to append the shadow.
// Thats because awakeFromNib() is called before the UICollectionViewCustomLayout
// have a chance to layout it, but I want to make
// use of shadowPath to gain performance, thats why
// I make use of the additional UIView with autolayout stuffs.
#IBOutlet weak var shadowView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
shadowView.layer.shadowOffset = CGSizeMake(0, 0)
shadowView.layer.shadowColor = UIColor.yellowColor().CGColor
shadowView.layer.shadowRadius = 3
shadowView.layer.shadowOpacity = 1
let shadowFrame: CGRect = shadowView.layer.bounds
let shadowPath: CGPathRef = UIBezierPath(rect: shadowFrame).CGPath
shadowView.layer.shadowPath = shadowPath
shadowView.clipsToBounds = false
self.clipsToBounds = false
}
You could try to define the shadows as supplementary views, aligned with their respective cells, and give them a lower z order than the cells.

Resources