UIView transparent gradient

2019-01-30 06:32发布

问题:

Given an arbitrary UIView on iOS, is there a way using Core Graphics (CAGradientLayer comes to mind) to apply a "foreground-transparent" gradient to it?

I can't use a standard CAGradientLayer because the background is more complex than a UIColor. I also can't overlay a PNG because the background will change as my subview is scrolled along its parent vertical scrollview (see image).

I have a non-elegant fallback: have my uiview clip its subviews and move a pre-rendered gradient png of the background as the parent scrollview is scrolled.

回答1:

This was an embarrassingly easy fix: apply a CAGradientLayer as my subview's mask.

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;

Thanks to Cocoanetics for pointing me in the right direction!



回答2:

This is how I'll do.

Step 1 Define a custom gradient view (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
    }
}

Step 2 - Drag and drop a UIView in your storyboard and set its custom class to GradientView

As an example, this is how the above gradient view looks like:


https://github.com/yzhong52/GradientViewDemo



回答3:

I just ran into the same issue and wound up writing my own class. It seems like serious overkill, but it was the only way I could find to do gradients with transparency. You can see my writeup and code example here

It basically comes down to a custom UIView that creates two images. One is a solid color, the other is a gradient that is used as an image mask. From there I applied the resulting image to the uiview.layer.content.

I hope it helps, Joe



回答4:

I hate to say it, but I think that you are into the CUSTOM UIView land. I think that I would try to implement this in a custom UIView overiding the drawRect routine.

With this, you could have that view, place on top of your actual scrollview, and have your gradient view (if you will) "pass-on" all touch events (i.e. relinquish first responder).



回答5:

I used the accepted (OP's) answer above and ran into the same issue noted in an upvoted comment - when the view scrolls, everything that started offscreen is now transparent, covered by the mask.

The solution was to add the gradient layer as the superview's mask, not the scroll view's mask. In my case, I'm using a text view, which is contained inside a view called contentView.

I added a third color and used locations instead of startPoint and endPoint, so that items below the text view are still visible.

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

Before, the text that started offscreen was permanently invisible. With my modifications, scrolling works as expected, and the "Close" button is not covered by the mask.