Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fade edges of UITableView

I've made a little research about my problem and unfortunately there was no solution for my problem. The closest was Fade UIImageView as it approaches the edges of a UIScrollView but it's still not for me.

I want my table to apply an "invisibility gradient" on the top. If the cell is at a 50px distance from the top edge it starts to vanish. The closer it is to the upper edge, the more invisible the part is. The cells height is about 200 pixels, so the lower part of the cell need to be visible in 100%. But nevermind - I need a table view (or table view container) to do this task, because similar tables can display other cells.

If the table is a subview of a solid color view, I can achieve that by adding an image which is a horizontal gradient that I can streach to any width. The top pixel of that image starts with the exact color of the background, and going down the same color has less alpha.

But... we have a UITableView with transparent color. Below the table there is no solid color, but a pattern image/texture, that can also be different on other screens of the app.

Do you have any Idea how I can achieve this behaviour?

Regards

like image 538
Chris Rutkowski Avatar asked May 13 '12 08:05

Chris Rutkowski


2 Answers

I took this tutorial and made some changes and additions:

  • It now works on all tableviews - even if they are part of bigger screen.
  • It works regardless of the background or whatever is behind the tableview.
  • The mask changes depends on the position of the table view - when scrolled to top only the bottom faded, in when scrolled to bottom only top is faded...

1. Start by importing QuartzCore and setting a mask layer in your controller:

EDIT: No need for reference to CAGradientLayer in class.

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface mViewController : UIViewController
.
.
@end

2. Add this to viewWillAppear viewDidLayoutSubviews: (See @Darren's comment on this one)

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    if (!self.tableView.layer.mask)
    {
        CAGradientLayer *maskLayer = [CAGradientLayer layer];

        maskLayer.locations = @[[NSNumber numberWithFloat:0.0], 
                                [NSNumber numberWithFloat:0.2], 
                                [NSNumber numberWithFloat:0.8], 
                                [NSNumber numberWithFloat:1.0]];

        maskLayer.bounds = CGRectMake(0, 0,
                            self.tableView.frame.size.width,
                            self.tableView.frame.size.height);
        maskLayer.anchorPoint = CGPointZero;

       self.tableView.layer.mask = maskLayer;
    }
    [self scrollViewDidScroll:self.tableView];
}

3. Make sure you are a delegate of UIScrollViewDelegate by adding it in the .h of your controller:

@interface mViewController : UIViewController <UIScrollViewDelegate>

4. To finish, implement scrollViewDidScroll in your controller .m:

#pragma mark - Scroll View Delegate Methods

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGColorRef outerColor = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
    CGColorRef innerColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
    NSArray *colors;

    if (scrollView.contentOffset.y + scrollView.contentInset.top <= 0) {
        //Top of scrollView
        colors = @[(__bridge id)innerColor, (__bridge id)innerColor,
                   (__bridge id)innerColor, (__bridge id)outerColor];
    } else if (scrollView.contentOffset.y + scrollView.frame.size.height
               >= scrollView.contentSize.height) {
        //Bottom of tableView
        colors = @[(__bridge id)outerColor, (__bridge id)innerColor,
                   (__bridge id)innerColor, (__bridge id)innerColor];
    } else {
        //Middle
        colors = @[(__bridge id)outerColor, (__bridge id)innerColor,
                   (__bridge id)innerColor, (__bridge id)outerColor];
    }
    ((CAGradientLayer *)scrollView.layer.mask).colors = colors;

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    scrollView.layer.mask.position = CGPointMake(0, scrollView.contentOffset.y);
    [CATransaction commit];
}

Again: most of the solution is from this tutorial in cocoanetics.

like image 165
Aviel Gross Avatar answered Oct 31 '22 03:10

Aviel Gross


This is a translation of Aviel Gross's answer to Swift

import UIKit

class mViewController: UIViewController, UIScrollViewDelegate {

    //Emitted boilerplate code

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if self.tableView.layer.mask == nil {

            //If you are using auto layout
            //self.view.layoutIfNeeded()

            let maskLayer: CAGradientLayer = CAGradientLayer()

            maskLayer.locations = [0.0, 0.2, 0.8, 1.0]
            let width = self.tableView.frame.size.width
            let height = self.tableView.frame.size.height
            maskLayer.bounds = CGRect(x: 0.0, y: 0.0, width: width, height: height)
            maskLayer.anchorPoint = CGPoint.zero

            self.tableView.layer.mask = maskLayer
        }

        scrollViewDidScroll(self.tableView)
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {

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

        var colors = [CGColor]()

        if scrollView.contentOffset.y + scrollView.contentInset.top <= 0 {
            colors = [innerColor, innerColor, innerColor, outerColor]
        } else if scrollView.contentOffset.y + scrollView.frame.size.height >= scrollView.contentSize.height {
            colors = [outerColor, innerColor, innerColor, innerColor]
        } else {
            colors = [outerColor, innerColor, innerColor, outerColor]
        }

        if let mask = scrollView.layer.mask as? CAGradientLayer {
            mask.colors = colors

            CATransaction.begin()
            CATransaction.setDisableActions(true)
            mask.position = CGPoint(x: 0.0, y: scrollView.contentOffset.y)
            CATransaction.commit()
        }

    }

    //Emitted boilerplate code
}
like image 44
Asdrubal Avatar answered Oct 31 '22 04:10

Asdrubal