Fading out any content which approaches edges of UIScollView
Asked Answered
V

3

11

As the title says, I am trying to give to some UIImageViews a fading out effect as they get closer and closer to any of the four edges of my UIScrollView. Since the user can drag the UIImages, if he drags them towards the edges, they start fading out, instead of giving that cut out effect as if there were borders to the UIScrollView. I tried this tutorial:

http://www.cocoanetics.com/2011/08/adding-fading-gradients-to-uitableview/

suggested in another stack overflow question, but it can only be applied to UITableViews. I would like the image to start fading as it gets one centimeter away from the border.

Verbalize answered 31/5, 2013 at 21:33 Comment(1)
Why won't it work in a UITableView?Bauxite
S
19

Similar to what was done in the Cocoanetics post you link to, you can create a CAGradientLayer to cover your scroll view. Make it fade out to the left, right, top and bottom edges, using the background color of your scroll view (in my example, white):

   CGColorRef innerColor = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
   CGColorRef outerColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;

   // first, define a horizontal gradient (left/right edges)
   CAGradientLayer* hMaskLayer = [CAGradientLayer layer];
   hMaskLayer.opacity = .7;
   hMaskLayer.colors = [NSArray arrayWithObjects:(id)outerColor,
                        (id)innerColor, (id)innerColor, (id)outerColor, nil];
   hMaskLayer.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],
                           [NSNumber numberWithFloat:0.15],
                           [NSNumber numberWithFloat:0.85],
                           [NSNumber numberWithFloat:1.0], nil];
   hMaskLayer.startPoint = CGPointMake(0, 0.5);
   hMaskLayer.endPoint = CGPointMake(1.0, 0.5);
   hMaskLayer.bounds = self.scrollView.bounds;
   hMaskLayer.anchorPoint = CGPointZero;

   CAGradientLayer* vMaskLayer = [CAGradientLayer layer];
   // without specifying startPoint and endPoint, we get a vertical gradient
   vMaskLayer.opacity = hMaskLayer.opacity;
   vMaskLayer.colors = hMaskLayer.colors;
   vMaskLayer.locations = hMaskLayer.locations;
   vMaskLayer.bounds = self.scrollView.bounds;
   vMaskLayer.anchorPoint = CGPointZero;

   // you must add the masks to the root view, not the scrollView, otherwise
   //  the masks will move as the user scrolls!
   [self.view.layer addSublayer: hMaskLayer];
   [self.view.layer addSublayer: vMaskLayer];

Disclaimer: this does sort of double-up the gradient/fade at the four corners. You can take a look at the results and decide whether they're good enough for you. If not, you could also try drawing a transparent image in something like Photoshop, and adding a UIImageView subview on top as the mask, using the image you drew.

enter image description here

Youtube screen capture

Sulfurous answered 31/5, 2013 at 22:28 Comment(6)
Is this a static cover for the entire scrollView or the dynamic visible rect?Amylo
It's a static cover, but it's added to the root view, not the scroll view itself. You don't want the cover to actually scroll with the content. Or, by dynamic, are you asking whether the cover starts hidden, and then dynamically appears once scrolling has started? No, it doesn't do that. I didn't see that in the question's description, and think that might look funny anyway.Sulfurous
By dynamic I mean if the content size of a scrollView is something like 2000 by 2000, does the blur happen on the edges of the 2000 by 2000 or does it happen within the visible area dynamically as the visible area is moved by the user?Amylo
This solution has nothing to do with content size. It doesn't care about fading elements that are off-screen, only what are visible. That's why the fade effect is applied at the borders of the visible area. It's added to the root view, which does not move. Therefore, it doesn't have to worry about which part of the scroll view is visible. It's not actually doing anything to the scroll view. A transparent gradient, the same color as the background, is applied above the scroll view, to make it appear as if content fades near the edges. Are you reading the question differently?Sulfurous
Not at all. You have some really elegant code and I wanted to confirm what I thought you had done (too lazy to try out your code right now).Amylo
I'll see your too lazy right now, and raise you a youtube screencast. A video is clearly worth 1000^2 words :)Sulfurous
A
5

Swift version of Nate answer, but only for top and bottom:

        let innerColor = UIColor(white: 1.0, alpha: 0.0).CGColor
        let outerColor = UIColor(white: 1.0, alpha: 1.0).CGColor;

        // define a vertical gradient (up/bottom edges)
        let colors = [outerColor, innerColor,innerColor,outerColor]
        let locations = [0.0, 0.15,0.85,1.0]

        var vMaskLayer : CAGradientLayer = CAGradientLayer()// layer];
        // without specifying startPoint and endPoint, we get a vertical gradient
        vMaskLayer.opacity = 0.7
        vMaskLayer.colors = colors;
        vMaskLayer.locations = locations;
        vMaskLayer.bounds = self.scrollView.bounds;
        vMaskLayer.anchorPoint = CGPointZero;

        // you must add the mask to the root view, not the scrollView, otherwise
        //  the masks will move as the user scrolls!
        self.view.layer.addSublayer(vMaskLayer)
Armilla answered 30/11, 2015 at 12:8 Comment(0)
A
2

Couple of postings on this issue here:

Changing the alpha inside UIScrollView

setting Alpha for UIView that is a subview of UIScrollVIew very slow

and some sample code here:

https://gist.github.com/MaximKeegan/2478842


If you want to go your own way then first get the visible part of the UIScrollView:

Getting the visible rect of an UIScrollView's content

and then fade the UIView:

UIView border with fade or blur effect

Amylo answered 31/5, 2013 at 21:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.