2

Due to our designer being a sadist, I have a UITableView with a segmented control that switches between two different types of cells in separate feeds. The cells are dequeued with different identifiers and classes — this all works fine. The cells share a parent but are different sizes and for optimization reasons I set the layer.shadowpath manually in layoutSubviews() of the parent. I need the shadows: designer's wishes.

The issue is that after I switch to the second segment, some of the way down the table there are shadows dangling from what I believe are the cells above. As you can see from the first image, there are two shadows, and if I scroll down to occlude the top-most visible cell the shadow disappears, which leads me to the believe that the shadows are offset. Further scrolling makes these shadows disappear and not reappear again until switching tabs again. The rest of the shadows are fine.

two shadows

two shadows

scroll down slightly

one shadow gone

When switching back to the previous tab, where the cells are taller, there are also shadow issues, but those shadows are too short. As noted, the code that sets the shadow path is in the parent class, and the parent class is responsible for making and laying-out the top-most "card" view that contains the custom subCells.

I do everything programmatically: setting up the views and the Autolayout. Currently cell heights are hard-coded. I'm not sure what information is relevant as I am completely at a loss, so here is how I set the shadowPath.

override func layoutSubviews() {
    super.layoutSubviews()
    cardView.layer.shadowPath = UIBezierPath(rect: cardView.bounds).CGPath
}

For simplicity the card is layout out in the contentView with the following visual format:

"V:|-marginV-[card]-marginV-|"
"H:|-marginH-[card]-marginH-|"
Alex Popov
  • 2,509
  • 1
  • 19
  • 30
  • I've narrowed it down to the cardView.layer.shadowPath, so if anybody knows how I can set that in a smart way after all the Autolayout constraints are set, I'd appreciate that. – Alex Popov Apr 27 '15 at 02:05

2 Answers2

3

For whatever reason, even though I was using separate classes and separate reuseIdentifiers, the first reused cells just out of the view port were still sized as the tall cells in the other segment. When I changed

let cell = tableView.dequeueReusableCellWithIdentifier(booksReuseIdentifier) as! ProfileBookCell to include the indexPath as

let cell = tableView.dequeueReusableCellWithIdentifier(booksReuseIdentifier, forIndexPath: indexPath) as! ProfileBookCell the recycling issue was remedied and bounds were properly computed. I tried layoutIfNeeded in a dozen different places to no effect, but this fixed it.

Alex Popov
  • 2,509
  • 1
  • 19
  • 30
2

I had the same exact problem and I tried the current marked solution but that, nor anything else seemed to work. After trying so many other things I finally tried moving my add shadow code inside the layoutSubviews function of my subclassed UITableViewCell and it finally worked! I think this worked because the cell's final size isn't always calculated properly until the layouSubviews call and it needs the proper size to draw the shadow.

override func layoutSubviews() {
     super.layoutSubviews()
    addShadow(cell: self)
}

private func addShadow(cell:UITableViewCell) {
    cell.layer.shadowOffset = CGSize(width:1, height:1)
    cell.layer.shadowColor = UIColor.black.cgColor
    cell.layer.shadowRadius = 1
    cell.layer.shadowOpacity = 0.6

    cell.clipsToBounds = false

    let shadowFrame: CGRect = (cell.layer.bounds)
    let shadowPath: CGPath = UIBezierPath(rect: shadowFrame).cgPath
    cell.layer.shadowPath = shadowPath
}