在 UITextView 上滚动内阴影
Posted
技术标签:
【中文标题】在 UITextView 上滚动内阴影【英文标题】:Scrolling inner shadow on UITextView 【发布时间】:2012-11-30 21:48:00 【问题描述】:我想继承 UITextView 以便能够绘制带有自定义边框和顶部+左内阴影的圆形矩形。
我在为任何(静态边界)视图创建此效果(通过阅读 this 帖子)方面取得了巨大成功,但在滚动视图时遇到了问题。
我在自定义类的-setFrame实例方法中做的这个效果:
- (void)setFrame:(CGRect)frame
[super setFrame:frame];
UIColor *borderColor = [UIColor colorWithRed:BORDER_COLOR_RED green:BORDER_COLOR_GREEN blue:BORDER_COLOR_BLUE alpha:BORDER_COLOR_ALPHA];
// Store index of the shadow sublayer for future use
[self setShadowLayerIndex:[LayerFormatter formatAsRoundRectWithShadowOn:self withBackgroundColor:[UIColor whiteColor] andBorderColor:borderColor]];
formatAsRoundRectWithShadowOn: 是一个类方法定义为:
+(NSUInteger)formatAsRoundRectWithShadowOn:(UIView*)view withBackgroundColor:(UIColor *)backgroundColor andBorderColor:(UIColor *)borderColor
if([view isKindOfClass:[UITextField class]])
((UITextField*)view).borderStyle = UITextBorderStyleNone;
view.backgroundColor = backgroundColor;
view.layer.borderWidth = 1.0;
view.layer.borderColor = [borderColor CGColor];
view.layer.cornerRadius = CORNER_RADIUS;
view.layer.masksToBounds = YES;
//Add some insets to the text: https://***.com/a/4423805
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
if([view isKindOfClass:[UITextField class]])
((UITextField*)view).leftView = paddingView;
((UITextField*)view).leftViewMode = UITextFieldViewModeAlways;
// Create and apply a shadow layer. Help here: https://***.com/questions/4431292/inner-shadow-effect-on-uiview-layer
CAShapeLayer* shadowLayer = [CAShapeLayer layer];
[shadowLayer setFrame:view.bounds];
[shadowLayer setShadowColor:[[UIColor blackColor] CGColor]];
[shadowLayer setShadowRadius:3.0f];
[shadowLayer setShadowOpacity:0.35f];
[shadowLayer setShadowOffset:CGSizeMake(2.0f, 2.0f)];
[shadowLayer setFillColor:[backgroundColor CGColor]];
// Causes the inner region in this example to NOT be filled.
[shadowLayer setFillRule:kCAFillRuleEvenOdd];
// Create inner and outer rectangle paths.
CGMutablePathRef path = CGPathCreateMutable();
// Outer path should be bigger than the field
UIBezierPath *bpOuter = [UIBezierPath bezierPathWithRect:CGRectInset(shadowLayer.bounds, -10, -10)];
// Inner path is the visible part of the view
UIBezierPath *bpInner = [UIBezierPath bezierPathWithRoundedRect:shadowLayer.bounds cornerRadius:CORNER_RADIUS];
// Add outer path and then add the inner path so it's subtracted from the outer path.
CGPathAddPath(path, NULL, bpOuter.CGPath);
CGPathAddPath(path, NULL, bpInner.CGPath);
CGPathCloseSubpath(path);
[shadowLayer setPath:path];
CGPathRelease(path);
[[view layer] addSublayer:shadowLayer];
NSUInteger addedAtIndex = [[[view layer] sublayers] indexOfObject:shadowLayer];
return addedAtIndex;
为了在文本视图滚动时处理正确的阴影+边框显示,我正在使用我的自定义类 -setBounds 方法来更新阴影层框架:
-(void)setBounds:(CGRect)bounds
[super setBounds:bounds];
// Change the frame of the shadow layer to reflect new bounds
[[[[self layer] sublayers] objectAtIndex:self.shadowLayerIndex] setFrame:bounds];
我遇到的问题是向下滚动(插入新文本行时)或顶部(向上滚动到文本开头)时,底部的阴影+边框绘制不正确。
插入新行或滚动完成后(视图再次为静态),视图绘制正确。
欢迎对这个问题提出任何见解。
【问题讨论】:
【参考方案1】:我有时间深入研究问题并找到了我想分享的解决方案。
起初我意识到最好在-awakeFromNib
中设置阴影层,而不是在-setFrame
中。
为了在文本视图滚动时处理正确的阴影+边框显示,我改变了这样的方法:更新阴影层,我现在在我的自定义类中使用 -layoutSubviews
覆盖。
在-layoutSubviews
覆盖中,我正在重新创建阴影层以尊重新边界,然后调用[super layoutSubviews]
。
滚动,改变方向 - 它就像一个魅力!
- (void)layoutSubviews
[self updateShadow];
[super layoutSubviews];
- (void)updateShadow
if (shadowLayer)
[shadowLayer removeFromSuperlayer];
shadowLayer = [LayerFormatter addInnerShadowLayerOn:self withShadowColor:[UIColor blackColor]];
请注意,+(NSUInteger)formatAsRoundRectWithShadowOn:(UIView*)view withBackgroundColor:(UIColor *)backgroundColor andBorderColor:(UIColor *)borderColor
现在正在返回对视图层层次结构中已添加层的层引用(返工很简单):
+(CAShapeLayer *)addInnerShadowLayerOn:(UIView *)view withShadowColor:(UIColor *)shadowColor;
任何证明这种方法是正确的并且不仅仅是有效的证据/cmets 都将受到高度赞赏。
【讨论】:
以上是关于在 UITextView 上滚动内阴影的主要内容,如果未能解决你的问题,请参考以下文章