ios uitableview fade bottom cell and top cell as you scroll

The issue is that the scroll event will not always happen frequently enough that a cell that scrolls into view will go from the faded alpha to an alpha of 1.0 as it scrolls from the top/bottom to the middle. But when you scroll really quickly, the scrollViewDidScroll isn't called frequently enough to ensure that this is the case. And your loop that apparently is attempting to reset the alpha is updating the alpha of the wrong view (contentView rather than the cell itself).

You can remedy this by replacing your existing for loop:

for (UITableViewCell *cell in visibleCells) {
    cell.contentView.alpha = 1.0;
}

With

for (UITableViewCell *cell in visibleCells) {
    cell.alpha = 1.0;
}

Or, alternatively, eliminate that loop from there and then replace the lines that set the alpha of the top and bottom cells:

if (topCell) {
    topCell.alpha = topCellOpacity;
}
if (bottomCell) {
    bottomCell.alpha = bottomCellOpacity;
}  

With:

for (UITableViewCell *cell in self.tableView.visibleCells) {
    if (cell == topCell) {
        cell.alpha = topCellOpacity;
    } else if (cell == bottomCell) {
        cell.alpha = bottomCellOpacity;
    } else {
        cell.alpha = 1.0;
    }
}

By the way, another way to achieve a similar effect is to apply a gradient mask to the whole tableview and retire the scrollViewDidScroll method. The only trick here is that you cannot apply the gradient mask to the table view, itself (or else the gradient will scroll with the table view), but rather put the tableview inside some container UIView, and then apply the mask to that:

- (void)viewDidAppear:(BOOL)animated
{
    CAGradientLayer *gradient = [CAGradientLayer layer];
    gradient.frame = self.containerView.bounds;
    gradient.colors = @[(id)[UIColor clearColor].CGColor,
                        (id)[UIColor whiteColor].CGColor,
                        (id)[UIColor whiteColor].CGColor,
                        (id)[UIColor clearColor].CGColor];
    gradient.locations = @[@0.0, @0.1, @0.9, @1.0];
    self.containerView.layer.mask = gradient;
}

This is admittedly a slightly different effect, but sometimes it's desirable. It just depends upon what you're shooting for.


Here is how you do it for Swift 4

extension UITableView {

    func fadeEdges(with modifier: CGFloat) {

        let visibleCells = self.visibleCells

        guard !visibleCells.isEmpty else { return }
        guard let topCell = visibleCells.first else { return }
        guard let bottomCell = visibleCells.last else { return }

        visibleCells.forEach {
            $0.contentView.alpha = 1
        }

        let cellHeight = topCell.frame.height - 1
        let tableViewTopPosition = self.frame.origin.y
        let tableViewBottomPosition = self.frame.maxY

        guard let topCellIndexpath = self.indexPath(for: topCell) else { return }
        let topCellPositionInTableView = self.rectForRow(at:topCellIndexpath)

        guard let bottomCellIndexpath = self.indexPath(for: bottomCell) else { return }
        let bottomCellPositionInTableView = self.rectForRow(at: bottomCellIndexpath)

        let topCellPosition = self.convert(topCellPositionInTableView, to: self.superview).origin.y
        let bottomCellPosition = self.convert(bottomCellPositionInTableView, to: self.superview).origin.y + cellHeight
        let topCellOpacity = (1.0 - ((tableViewTopPosition - topCellPosition) / cellHeight) * modifier)
        let bottomCellOpacity = (1.0 - ((bottomCellPosition - tableViewBottomPosition) / cellHeight) * modifier)

        topCell.contentView.alpha = topCellOpacity
        bottomCell.contentView.alpha = bottomCellOpacity
    }

}

and this is how you will call it...

you call this inside scrollViewDidScroll method like this...

public func scrollViewDidScroll(_ scrollView: UIScrollView) {
   tableView.fadeEdges(with: 1.0)
}

The modifier Increases the speed of fading (1.0 for fully transparent when the cell is entirely off the screen, 2.0 for fully transparent when the cell is half of the screen, for example.