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 UIScro
This is my version of the fading table view by inheriting UITableView. Tested for iOS 7 & 8.
CEFadingTableView.m
#import "CEFadingTableView.h"
@interface CEFadingTableView()
@property (nonatomic) float percent; // 1 - 100%
@end
@implementation CEFadingTableView
- (void)awakeFromNib
{
[super awakeFromNib];
self.percent = 5.0f;
[self addObserver:self forKeyPath:@"bounds" options:0 context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if(object == self && [keyPath isEqualToString:@"bounds"])
{
[self initMask];
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:@"bounds"];
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateMask];
}
- (void)initMask
{
CAGradientLayer *maskLayer = [CAGradientLayer layer];
maskLayer.locations = @[@(0.0f), @(_percent / 100), @(1 - _percent / 100), @(1.0f)];
maskLayer.bounds = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
maskLayer.anchorPoint = CGPointZero;
self.layer.mask = maskLayer;
[self updateMask];
}
- (void)updateMask
{
UIScrollView *scrollView = self;
CGColorRef outer = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
CGColorRef inner = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
NSArray *colors = @[(__bridge id)outer, (__bridge id)inner, (__bridge id)inner, (__bridge id)outer];
if(scrollView.contentOffset.y <= 0) // top
{
colors = @[(__bridge id)inner, (__bridge id)inner, (__bridge id)inner, (__bridge id)outer];
}
else if((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height) // bottom
{
colors = @[(__bridge id)outer, (__bridge id)inner, (__bridge id)inner, (__bridge id)inner];
}
((CAGradientLayer *)scrollView.layer.mask).colors = colors;
[CATransaction begin];
[CATransaction setDisableActions:YES];
scrollView.layer.mask.position = CGPointMake(0, scrollView.contentOffset.y);
[CATransaction commit];
}
@end
Swift version of @victorfigol's excellent solution:
class FadingTableView : UITableView {
var percent = Float(0.05)
private let outerColor = UIColor(white: 1.0, alpha: 0.0).cgColor
private let innerColor = UIColor(white: 1.0, alpha: 1.0).cgColor
override func awakeFromNib() {
super.awakeFromNib()
addObserver(self, forKeyPath: "bounds", options: NSKeyValueObservingOptions(rawValue: 0), context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if object is FadingTableView && keyPath == "bounds" {
initMask()
}
}
deinit {
removeObserver(self, forKeyPath:"bounds")
}
override func layoutSubviews() {
super.layoutSubviews()
updateMask()
}
func initMask() {
let maskLayer = CAGradientLayer()
maskLayer.locations = [0.0, NSNumber(value: percent), NSNumber(value:1 - percent), 1.0]
maskLayer.bounds = CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height)
maskLayer.anchorPoint = CGPoint.zero
self.layer.mask = maskLayer
updateMask()
}
func updateMask() {
let scrollView : UIScrollView = self
var colors = [CGColor]()
if scrollView.contentOffset.y <= -scrollView.contentInset.top { // top
colors = [innerColor, innerColor, innerColor, outerColor]
}
else if (scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height { // bottom
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()
}
}
}
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
}
I took this tutorial and made some changes and additions:
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.