UIView透明渐变

40

在iOS上给定任意的UIView,是否可以使用核心图形(CAGradientLayer)为其应用一个“前景透明”的渐变效果?

由于背景比UIColor更加复杂,因此无法使用标准的CAGradientLayer。同时也无法覆盖PNG图片,因为随着我的子视图在父垂直滚动视图中滚动,背景会发生变化(参见图像)。

我有一个不太优雅的后备方案:让我的UIView剪裁其子视图,并将预渲染的背景渐变png移动到父滚动视图滚动时。

transparent uiview gradient problem


背景是什么?当滚动视图滚动时,它如何“改变”? - rob mayoff
正如@jab在下面的答案中提到的那样,将这个问题通常地看作是将渐变蒙版应用于任何视图,而不是应用于_scroll_视图(就像OP请求的那样)可能更有用。使用下面描述的方法之一创建这样的容器视图,然后将滚动视图添加为子视图,可以创建所需的效果。看起来有些人试图将渐变应用于滚动视图本身,并没有得到他们想要的东西,因此存在一些混淆。 - SlimeBaron
5个回答

100
这是一个非常容易的解决方法:将CAGradientLayer应用作我的子视图的掩码。
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = _fileTypeScrollView.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor, nil];
gradientLayer.startPoint = CGPointMake(0.8f, 1.0f);
gradientLayer.endPoint = CGPointMake(1.0f, 1.0f);
_fileTypeScrollView.layer.mask = gradientLayer;

感谢Cocoanetics指导我的方向!


7
我用这段代码给一个类似的水平UIScrollView添加了渐变。看起来一切正常,但当你实际滚动时,从右边进入的视图是透明的。就好像渐变应用于实际坐落在UIScrollView上的视图,而不是作为在它们上面的图层。我做错了什么? - David Ben Ari
1
如何使用此代码创建垂直渐变? - Sebastian Boldt
未来的读者:这是另一个有用的线程 - https://dev59.com/y2Ag5IYBdhLWcg3w3uMR - kbpontius
1
正如 https://dev59.com/emgv5IYBdhLWcg3wF89P#53307483 中所指出的那样,渐变层应该应用于滚动视图的父视图,而不是滚动视图本身。 - elitalon

10

我会这样做。

步骤1 定义自定义渐变视图(Swift 4):

import UIKit

class GradientView: UIView {
    override open class var layerClass: AnyClass {
        return CAGradientLayer.classForCoder()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let gradientLayer = self.layer as! CAGradientLayer
        gradientLayer.colors = [
            UIColor.white.cgColor,
            UIColor.init(white: 1, alpha: 0).cgColor
        ]
        backgroundColor = UIColor.clear
    }
}

步骤二 - 在你的Storyboard中拖放一个UIView并将其自定义类设置为GradientView

在这里输入图片描述

例如,这是上述渐变视图的外观:


https://github.com/yzhong52/GradientViewDemo


@Elsammak 我认为这是因为您没有将UIView的背景颜色设置为透明。请参阅Smaily Carrilho的编辑以获取详细信息。 - Yuchen
另外提醒一下,还需要加上 mapView.addSubview(mapGradientView) - Codetard
@SatnamSync 感谢您的编辑。但是第二步相当于 mapView.addSubview(mapGradientView)。本质上,如果我们在故事板中有视图,我们就不应该再次调用它。但是,如果您想在代码中执行操作,那么这将是正确的方法。 - Yuchen
@YuchenZhong 我刚试了一下,在编程和Storyboard两种方式都需要。我不知道在使用Google地图时是否需要,但是UIView(类 - MKMapView,这就是我使用的方式)确实需要提到这点。 - Codetard
1
@SatnamSync,你的代码可能有一个bug。我放了一个演示版本,看看是否有帮助。https://github.com/yzhong52/GradientViewDemo - Yuchen

4
我使用了上面被接受的答案,并遇到了与一个有赞同票的评论中指出的相同问题-当视图滚动时,一切从屏幕外开始的东西现在都是透明的,被掩盖了。
解决方法是将渐变层添加为父视图的蒙版,而不是滚动视图的蒙版。在我的情况下,我正在使用一个文本视图,它包含在一个名为contentView的视图中。
我添加了第三种颜色,并使用了locations而不是startPointendPoint,这样文本视图下方的项目仍然可见。
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.contentView!.bounds
gradientLayer.colors = [UIColor.white.cgColor, UIColor.clear.cgColor, UIColor.white.cgColor]

// choose position for gradient, aligned to bottom of text view
let bottomOffset = (self.textView!.frame.size.height + self.textView!.frame.origin.y + 5)/self.contentView!.bounds.size.height
let topOffset = bottomOffset - 0.1
let bottomCoordinate = NSNumber(value: Double(bottomOffset))
let topCoordinate = NSNumber(value: Double(topOffset))
gradientLayer.locations = [topCoordinate, bottomCoordinate, bottomCoordinate]

self.contentView!.layer.mask = gradientLayer

之前,屏幕外的文本是永久不可见的。通过我的修改,滚动现在可以按预期工作,并且“关闭”按钮不会被遮挡。

截图


2

渐变示例

我遇到了同样的问题,最终写了自己的类。这似乎有点过度设计,但这是我找到的唯一实现透明度渐变的方法。你可以在这里看到我的详细说明和代码示例。

基本上,它涉及到一个自定义UIView,它创建两个图像。一个是纯色,另一个是用作图像蒙版的渐变。从那里,我将结果应用于uiview.layer.content。

希望能帮到你, Joe


0

我不想这么说,但我认为你需要使用自定义UIView。我建议你在自定义UIView中重写drawRect方法来实现它。

这样,你就可以将该视图放置在实际滚动视图的顶部,并使你的渐变视图(如果你愿意)“传递”所有触摸事件(即放弃第一响应者)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接