简体   繁体   English

在UITextView上滚动内部阴影

[英]Scrolling inner shadow on UITextView

I would like to subclass UITextView to be able to draw round rect with custom border plus top+left inner shadow. 我想对UITextView进行子类化,以便能够使用自定义边框加上顶部和左侧内部阴影绘制圆形矩形。

I had big success in creating this effect (by reading this post) for any (static bounds) view but had problems with scrolling views. 我在创造这种效果大获成功(通过读取这个帖子)任何(静界)的看法,但曾与滚动视图的问题。

This effect I'm doing in -setFrame instance method of my custom class: 我正在自定义类的-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: is a class method defined as: 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://stackoverflow.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://stackoverflow.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;}

To handle correct shadow+border display when the text view is scrolling i'm using my custom class -setBounds method to update the shadow layer frame: 为了在文本视图滚动时处理正确的阴影+边框显示,我正在使用我的自定义类-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];}

The issue I'm experiencing is a incorrect shadow+frame drawing at the bottom when scrolling down (when inserting new lines of text) or at the top (when scrolling up to the beginning of the text). 我遇到的问题是向下滚动(插入新行文本时)在底部或顶部(向上滚动到文本开头时)在底部有不正确的阴影+边框绘制。

After the new line is inserted or scroll completes (the view is again static) the view is drawn correct. 在插入新行或滚动完成(视图再次为静态)之后,将正确绘制视图。

Any insight on the issue is more than welcome. 对这个问题的任何见解都值得欢迎。

I had some time to dig into the problem and found a solution I want to share. 我花了一些时间来研究问题,并找到了我想分享的解决方案。

At first I realise that it's better to setup the shadow layer in -awakeFromNib instead in -setFrame . 起初,我意识到最好在-awakeFromNib设置阴影层,而不是在-setFrame

To handle correct shadow+border display when the text view is scrolling I've changed the approach like this: to update the shadow layer I'm now using -layoutSubviews override in my custom class. 为了在文本视图滚动时处理正确的阴影+边框显示,我改变了这种方法:为了更新阴影层,我现在在自定义类中使用-layoutSubviews覆盖。 In -layoutSubviews override I'm recreating the shadow layer to respect new bounds then calling [super layoutSubviews] . -layoutSubviews我正在重新创建阴影层以尊重新边界,然后调用[super layoutSubviews]

Scrolling, changing orientation - it works like a charm! 滚动,改变方向-就像一个魅力!

- (void)layoutSubviews
{
    [self updateShadow];
    [super layoutSubviews];
}

- (void)updateShadow
{
    if (shadowLayer)
        [shadowLayer removeFromSuperlayer];

    shadowLayer = [LayerFormatter addInnerShadowLayerOn:self withShadowColor:[UIColor blackColor]];
}   

Note that +(NSUInteger)formatAsRoundRectWithShadowOn:(UIView*)view withBackgroundColor:(UIColor *)backgroundColor andBorderColor:(UIColor *)borderColor is now returning layer reference to the already added layer in the view's layer hierarchy (the rework is simple): 请注意, +(NSUInteger)formatAsRoundRectWithShadowOn:(UIView*)view withBackgroundColor:(UIColor *)backgroundColor andBorderColor:(UIColor *)borderColor现在正在返回对视图图层层次结构中已添加图层的图层引用(重做很简单):

+(CAShapeLayer *)addInnerShadowLayerOn:(UIView *)view withShadowColor:(UIColor *)shadowColor;

Any evidence/comments that this approach is correct and not just working would be highly appreciated. 任何证明这种方法是正确的并且不仅有效的证据/评论都将受到高度赞赏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM