You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用UIScrollView时,如何在内容超出可视范围时淡化左右边缘?

给水平滚动UIScrollView添加边缘淡入淡出效果的问题

我有一个可水平滚动的UIScrollView,其中包含图片、UIView等各类内容。希望在内容超出左右边缘时,让边缘逐渐淡化至透明。尝试了以下代码,但无法正常工作:

class CustomScrollView: UIScrollView {
    
    override func layoutSubviews() {
        super.layoutSubviews()
        print("layoutSubviews")
        
        if layer.mask == nil {
            let mask = CAGradientLayer()
            mask.locations = [0.0, 0.2, 0.8, 1.0]
            
            mask.startPoint = CGPoint(x:0, y:0)
            mask.endPoint = CGPoint(x:1, y:0)

            layer.mask = mask
        }
        
        if let mask = layer.mask as? CAGradientLayer {
            
            mask.bounds = self.frame
            let fadedColor = UIColor(white: 1.0, alpha: 0.0).cgColor
            let realColor = UIColor(white: 1.0, alpha: 1.0).cgColor

            var colors = [CGColor]()

            colors = [fadedColor, realColor, realColor, fadedColor]
                        
            mask.colors = colors

            CATransaction.begin()
            CATransaction.setDisableActions(true)
            CATransaction.commit()
        }
    }
}

问题分析与修复

你的代码核心问题在于mask的bounds设置错误,以及动画禁用逻辑的位置不对:

  1. 使用self.frame来设置mask的bounds是错误的,frame是scrollView相对于父视图的坐标,应该用self.bounds匹配scrollView自身的可视区域;
  2. CATransaction禁用动画的块没有包裹mask的属性修改,导致可能出现不必要的过渡动画;
  3. 需要显式设置mask的position,确保它锚定在scrollView的中心位置。

修正后的代码如下:

class CustomScrollView: UIScrollView {
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        if layer.mask == nil {
            let mask = CAGradientLayer()
            mask.locations = [0.0, 0.2, 0.8, 1.0]
            mask.startPoint = CGPoint(x: 0, y: 0)
            mask.endPoint = CGPoint(x: 1, y: 0)
            layer.mask = mask
        }
        
        guard let mask = layer.mask as? CAGradientLayer else { return }
        
        // 使用bounds匹配scrollView自身可视区域
        mask.bounds = self.bounds
        // 将mask锚定在scrollView中心
        mask.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
        
        let fadedColor = UIColor(white: 1.0, alpha: 0.0).cgColor
        let realColor = UIColor(white: 1.0, alpha: 1.0).cgColor
        mask.colors = [fadedColor, realColor, realColor, fadedColor]
        
        // 禁用动画,避免mask更新时的过渡效果
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        layer.mask = mask
        CATransaction.commit()
    }
}

额外调整说明

如果需要修改淡化区域的宽度,可以调整mask.locations数组的值:

  • 比如将[0.0, 0.2, 0.8, 1.0]改为[0.0, 0.1, 0.9, 1.0],淡化区域会更宽;
  • 改为[0.0, 0.3, 0.7, 1.0]则淡化区域更窄。

内容的提问来源于stack exchange,提问作者sudoExclamationExclamation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:13:10