修复 UIScrollView 顶部和底部的 CALayer

Posted

技术标签:

【中文标题】修复 UIScrollView 顶部和底部的 CALayer【英文标题】:Fixing CALayer at top and bottom of UIScrollView 【发布时间】:2010-12-16 15:23:22 【问题描述】:

我正在继承 UIScrollView 并添加一些视觉元素。在顶部,应该有一个从黑色到透明的渐变,在底部有一个向底部淡出的蒙版。我添加了这些图层并且看起来正确,但是当我滚动时,它们会停留在我放入它们的坐标处(相对于滚动视图),而不是“固定”到视图的底部和顶部。此滚动视图仅垂直滚动。

这是 SettingsScrollView.m 的代码:

#import "SettingsScrollView.h"
#import <QuartzCore/QuartzCore.h>

#define SHADOW_HEIGHT 20.0
#define SHADOW_INVERSE_HEIGHT 10.0
#define SHADOW_RATIO (SHADOW_INVERSE_HEIGHT / SHADOW_HEIGHT)

@implementation SettingsScrollView


- (id)initWithCoder:(NSCoder *)aDecoder

    self = [super initWithCoder:aDecoder];

    [self setUpShadow];

    return self;


- (CAGradientLayer *)shadowAsInverse:(BOOL)inverse

    CAGradientLayer *newShadow = [[[CAGradientLayer alloc] init] autorelease];
    CGRect newShadowFrame = CGRectMake(0, 0, self.frame.size.width, inverse ? SHADOW_INVERSE_HEIGHT : SHADOW_HEIGHT);
    newShadow.frame = newShadowFrame;
    CGColorRef darkColor =[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:inverse ? (SHADOW_INVERSE_HEIGHT / SHADOW_HEIGHT) * 0.5 : 0.5].CGColor;
    CGColorRef lightColor = [self.backgroundColor colorWithAlphaComponent:0.0].CGColor;

    newShadow.colors = [NSArray arrayWithObjects: (id)(inverse ? lightColor : darkColor), (id)(inverse ? darkColor : lightColor), nil];
    return newShadow;


- (CAGradientLayer *)gradientMask

    CAGradientLayer *mask = [[[CAGradientLayer alloc] init] autorelease];
    CGRect maskFrame =  CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    mask.frame = maskFrame;
    CGColorRef darkColor =[UIColor clearColor].CGColor;
    CGColorRef lightColor =[UIColor blackColor].CGColor;

    mask.colors = [NSArray arrayWithObjects: (id)lightColor, (id)lightColor, (id)darkColor, nil];
    mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.9], [NSNumber numberWithFloat:1.0], nil]; 
    return mask;


- (void)setUpShadow

    CAGradientLayer *topShadowLayer = [self shadowAsInverse:NO];
    CAGradientLayer *bottomShadowLayer = [self gradientMask];

    [self.layer insertSublayer:topShadowLayer atIndex:0];

    [self.layer setMask:bottomShadowLayer];

    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

    CGRect topShadowLayerFrame = topShadowLayer.frame;
    topShadowLayerFrame.size.width = self.frame.size.width;
    topShadowLayerFrame.origin.y = 0;
    topShadowLayer.frame = topShadowLayerFrame;

    CGRect bottomShadowLayerFrame = bottomShadowLayer.frame;
    bottomShadowLayerFrame.size.width = self.frame.size.width;
    bottomShadowLayerFrame.origin.y = self.frame.size.height - bottomShadowLayer.frame.size.height;
    bottomShadowLayer.frame = bottomShadowLayerFrame;

    [CATransaction commit];


@end

我知道顶部的一种解决方案可能只是添加一个包含渐变的单独视图,但对于底部我相信我需要使用蒙版让它做我想做的事情(淡出到背景中在最底部)。背景是图像,所以我不能只是淡出白色或其他颜色,它需要淡出才能清晰。我一直在寻找一种在移动滚动视图时调用的方法,并使用它来更改遮罩的位置,但我还没有找到任何东西。有什么建议吗?

【问题讨论】:

【参考方案1】:

您可以通过覆盖 UIScrollView 上的 -layoutSubviews 来完成此操作,当它的边界发生变化时会调用它。

我在这样的视图上看到的另一种技术是,不是从视图子类CALayer 执行此层管理,而是使用您的子类作为滚动视图的层,然后在您的层的-layoutSublayers 中,执行当它四处移动时,同样的工作。我提到了后一种技术,因为层管理其子层与视图直接管理其层子层相比似乎更自然一些。

【讨论】:

啊,layoutSubviews 是我正在寻找的方法。谢谢!

以上是关于修复 UIScrollView 顶部和底部的 CALayer的主要内容,如果未能解决你的问题,请参考以下文章

将 UIScrollView 中的内容视图固定到其底部而不是其顶部边缘

子视图内的 UIScrollview 高度动态变化

在顶部和底部停止滚动UITableView?

UIScrollView 仅在底部禁用垂直反弹

开始时从底部锚定的 UIScrollview

将“页脚”固定到屏幕底部的 UIScrollView 自动布局