可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
回答1:
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.
回答2:
This is my version of the fading table view by inheriting UITableView. Tested for iOS 7 & 8.
- There is no need to implement scrollViewDidScroll, layoutSubviews can be used instead.
- By observing for bounds changes, the mask is
always properly placed when the rotation changes.
- You can use the percent parameter to change how much fading you want at the edges, I
find a small value looking better in some cases.
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
回答3:
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 // Swift 3.0 update
self.tableView.layer.mask = maskLayer
}
scrollViewDidScroll(self.tableView)
}
// Swift 3.0 update
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 = [AnyObject]()
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]
}
(scrollView.layer.mask as! CAGradientLayer).colors = colors
CATransaction.begin()
CATransaction.setDisableActions(true)
scrollView.layer.mask?.position = CGPoint(x: 0.0, y: scrollView.contentOffset.y)
CATransaction.commit()
}
//Emitted boilerplate code
}
回答4:
Swift 3 Version of @victorfigol's excellent solution:
class FadingTableView : UITableView {
var percent = Float(0.05)
fileprivate let outerColor = UIColor(white: 1.0, alpha: 0.0).cgColor
fileprivate 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 = [AnyObject]()
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()
}
}
}