ios uitableview在滚动时淡入底部单元格和顶部单元格

ios uitableview在滚动时淡入底部单元格和顶部单元格,ios,uitableview,fade,Ios,Uitableview,Fade,当我的uitableview中的单元格滚动到视图外时,我会将其淡出,或者当它们滚动到视图中时,我会将其淡入。我面临的问题是,如果我滚动得很快,有时完全可见的单元格仍然会变暗。下面是我的代码: - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // Fades out top and bottom cells in table view as they leave the screen NSArray *visible

当我的uitableview中的单元格滚动到视图外时,我会将其淡出,或者当它们滚动到视图中时,我会将其淡入。我面临的问题是,如果我滚动得很快,有时完全可见的单元格仍然会变暗。下面是我的代码:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // Fades out top and bottom cells in table view as they leave the screen
    NSArray *visibleCells = [self.tableView visibleCells];

    if (visibleCells != nil  &&  [visibleCells count] != 0) {       // Don't do anything for empty table view

        /* Get top and bottom cells */
        UITableViewCell *topCell = [visibleCells objectAtIndex:0];
        UITableViewCell *bottomCell = [visibleCells lastObject];

        /* Make sure other cells stay opaque */
        // Avoids issues with skipped method calls during rapid scrolling
        for (UITableViewCell *cell in visibleCells) {
            cell.contentView.alpha = 1.0;
        }

        /* Set necessary constants */
        NSInteger cellHeight = topCell.frame.size.height - 1;   // -1 To allow for typical separator line height
        NSInteger tableViewTopPosition = self.tableView.frame.origin.y;
        NSInteger tableViewBottomPosition = self.tableView.frame.origin.y + self.tableView.frame.size.height;

        /* Get content offset to set opacity */
        CGRect topCellPositionInTableView = [self.tableView rectForRowAtIndexPath:[self.tableView indexPathForCell:topCell]];
        CGRect bottomCellPositionInTableView = [self.tableView rectForRowAtIndexPath:[self.tableView indexPathForCell:bottomCell]];
        CGFloat topCellPosition = [self.tableView convertRect:topCellPositionInTableView toView:[self.tableView superview]].origin.y;
        CGFloat bottomCellPosition = ([self.tableView convertRect:bottomCellPositionInTableView toView:[self.tableView superview]].origin.y + cellHeight);

        /* Set opacity based on amount of cell that is outside of view */
        CGFloat modifier = 1.2;     /* 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 off the screen, etc) */
        CGFloat topCellOpacity = (1.0f - ((tableViewTopPosition - topCellPosition) / cellHeight) * modifier);
        CGFloat bottomCellOpacity = (1.0f - ((bottomCellPosition - tableViewBottomPosition) / cellHeight) * modifier);

        /* Set cell opacity */
        if (topCell) {
            topCell.alpha = topCellOpacity;
        }
        if (bottomCell) {
            bottomCell.alpha = bottomCellOpacity;
        }  
    }
}

你知道为什么当我快速滚动时,视图中的单元格有时会变暗吗?

问题是滚动事件不会经常发生,滚动到视图中的单元格在从上/下滚动到中间时,会从褪色的alpha变为1.0的alpha。但是当您快速滚动时,
scrollViewDidScroll
的调用频率不够高,无法确保这种情况。显然是试图重置
alpha
的循环正在更新错误视图的
alpha
contentView
,而不是单元格本身)

您可以通过替换现有的
for
循环来解决此问题:

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

或者,从那里消除该循环,然后替换设置顶部和底部单元格alpha的线条:

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


顺便说一下,实现类似效果的另一种方法是对整个tableview应用渐变遮罩,并取消
scrollViewDidScroll
方法。这里唯一的技巧是,您不能将渐变遮罩应用于表格视图本身(否则渐变将随表格视图滚动),而是将表格视图放在某个容器
UIView
中,然后将遮罩应用于该容器:

- (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;
}

这是一个公认的略有不同的效果,但有时是可取的。这取决于你的拍摄目的。

以下是你如何为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
    }

}
这就是你将如何称呼它

您在
scrollViewDidScroll
内部调用此方法,如下所示

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

修改器会增加淡入的速度(例如,1.0表示当单元格完全离开屏幕时完全透明,2.0表示当单元格位于屏幕的一半时完全透明。

这似乎不再引起问题……但我对代码中的for循环如何不处理这一问题感到困惑。如果你看,我在上面的代码中有这个for循环:
for(UITableViewCell*visibleCells中的单元格){cell.contentView.alpha=1.0;}
@AtulBhatia哦,我不确定你想在那里做什么。那是因为你设置的是
cell.contentView.alpha
,而不是
cell.alpha
。当你变暗时,你在改变
cell.alpha
,所以当你取消变暗时,你也必须这样做。(你肯定想使用
cell.alpha
以防你使用泄露指示器、单元格着色等)我更新了我的答案。我在寻找其他东西,但找到了你的渐变实现。这太棒了。完全可以使用了。你把这叫做什么?
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
    }

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