提问人:Vulkan 提问时间:9/1/2022 更新时间:9/2/2022 访问量:52
如何向 UIVisualEffectView 添加阴影角和圆角?
How do I add both shadow and rounded corners to a UIVisualEffectView?
问:
我正在为我希望它模糊的元素使用一个容器。为了添加圆角,我修改了图层,而对于阴影,我创建了第二个名为 containerShadow 的视图,并将其放置在其下方。
它有效,但并非完美无缺。阴影使模糊效果变暗。有没有办法完善它?
.h
@property (strong) UIVisualEffectView *containerView;
@property (strong) UIView *containerShadowView;
.m 域名
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.25;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// Random container frame for testing...
self.containerView.frame =
CGRectMake(20.0,
200.0,
380,
480);
self.containerShadowView.frame = self.containerView.frame;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:self.containerShadowView.bounds cornerRadius:self.containerView.layer.cornerRadius] CGPath];
}
答:
1赞
DonMag
9/2/2022
#1
您可以通过使用与效果视图匹配的“切口”遮罩来做到这一点。containerShadowView
containerView
所以,这就是它的样子 - 我将视图居中,并用于强调差异。380x480
0.9
.shadowOpacity
左边是你的原件,右边是蒙版:
有点难以判断到底发生了什么,因为这可能是一个不透明的层,我们将在它后面添加一个标签:
而且,为了阐明我们在做什么,让我们在隐藏效果视图的情况下看一下它:containerView
这是我用于此目的的源代码 - 任何地方的每个点击都会在 8 种不同的布局中循环:
#import <UIKit/UIKit.h>
@interface OrigShadowView : UIView
@property (strong) UIVisualEffectView *containerView;
@property (strong) UIView *containerShadowView;
@end
@implementation OrigShadowView
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.9;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// let's center a 380 x 480 rectangle in self
CGFloat w = 380.0;
CGFloat h = 480.0;
CGRect vRect = CGRectMake((frame.size.width - w) * 0.5, (frame.size.height - h) * 0.5, w, h);
self.containerView.frame = vRect;
self.containerShadowView.frame = self.containerView.frame;
// change origin to 0,0 because the following will be relative to the subviews
vRect.origin = CGPointZero;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius] CGPath];
}
@end
@interface MaskShadowView : UIView
@property (strong) UIVisualEffectView *containerView;
@property (strong) UIView *containerShadowView;
@end
@implementation MaskShadowView
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.9;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// let's center a 380 x 480 rectangle in self
CGFloat w = 380.0;
CGFloat h = 480.0;
CGRect vRect = CGRectMake((frame.size.width - w) * 0.5, (frame.size.height - h) * 0.5, w, h);
self.containerView.frame = vRect;
self.containerShadowView.frame = self.containerView.frame;
// change origin to 0,0 because the following will be relative to the subviews
vRect.origin = CGPointZero;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius] CGPath];
UIBezierPath *bigBez;
UIBezierPath *clipBez;
// we need a rectangle that will encompass the shadow radius
// double the shadowRadius is probably sufficient, but since it won't be seen
// and won't affect anything else, we'll make it 4x
CGRect expandedRect = CGRectInset(vRect, -self.containerShadowView.layer.shadowRadius * 4.0, -self.containerShadowView.layer.shadowRadius * 4.0);
bigBez = [UIBezierPath bezierPathWithRect:expandedRect];
// we want to "clip out" a rounded rect in the center
// which will be the same size as the visual effect view
clipBez = [UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius];
[bigBez appendPath:clipBez];
bigBez.usesEvenOddFillRule = YES;
CAShapeLayer *maskLayer = [CAShapeLayer new];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = UIColor.whiteColor.CGColor;
maskLayer.path = bigBez.CGPath;
self.containerShadowView.layer.mask = maskLayer;
}
@end
@interface BlurTestViewController : UIViewController
{
OrigShadowView *origView;
MaskShadowView *newView;
UILabel *bkgLabel;
// so we can step through on taps to see the results
NSInteger step;
UILabel *infoLabel;
}
@end
@implementation BlurTestViewController
- (void)viewDidLoad {
[super viewDidLoad];
bkgLabel = [UILabel new];
bkgLabel.textColor = UIColor.blueColor;
bkgLabel.font = [UIFont systemFontOfSize:48.0 weight:UIFontWeightBlack];
bkgLabel.textAlignment = NSTextAlignmentCenter;
bkgLabel.numberOfLines = 0;
bkgLabel.text = @"A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.";
bkgLabel.text = @"I'm using a container for elements which I'd like for it to be blurred. In order to add rounded corners I modified the layer while for the shadow I created a second view named containerShadow and placed it below it.";
origView = [OrigShadowView new];
newView = [MaskShadowView new];
[self.view addSubview:bkgLabel];
[self.view addSubview:origView];
[self.view addSubview:newView];
infoLabel = [UILabel new];
infoLabel.font = [UIFont systemFontOfSize:20.0 weight:UIFontWeightBold];
infoLabel.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:infoLabel];
step = 0;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// let's inset the "shadow blur" views 40-points
CGRect r = CGRectInset(self.view.frame, 40.0, 40.0);
origView.frame = r;
newView.frame = r;
// let's put the background label midway down the screen
r.origin.y += r.size.height * 0.5;
r.size.height *= 0.5;
bkgLabel.frame = r;
// put the info label near the top
infoLabel.frame = CGRectMake(40.0, 80.0, r.size.width, 40.0);
[self nextStep];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self nextStep];
}
- (void)nextStep {
bkgLabel.hidden = YES;
origView.hidden = YES;
newView.hidden = YES;
origView.containerView.hidden = NO;
newView.containerView.hidden = NO;
step++;
switch (step) {
case 1:
origView.hidden = NO;
infoLabel.text = @"1: Original View";
break;
case 2:
newView.hidden = NO;
infoLabel.text = @"2: Masked View";
break;
case 3:
bkgLabel.hidden = NO;
origView.hidden = NO;
infoLabel.text = @"3: Original View";
break;
case 4:
bkgLabel.hidden = NO;
newView.hidden = NO;
infoLabel.text = @"4: Masked View";
break;
case 5:
origView.hidden = NO;
origView.containerView.hidden = YES;
infoLabel.text = @"5: Original View - effect view hidden";
break;
case 6:
newView.hidden = NO;
newView.containerView.hidden = YES;
infoLabel.text = @"6: Masked View - effect view hidden";
break;
case 7:
bkgLabel.hidden = NO;
origView.hidden = NO;
origView.containerView.hidden = YES;
infoLabel.text = @"7: Original View - effect view hidden";
break;
default:
bkgLabel.hidden = NO;
newView.hidden = NO;
newView.containerView.hidden = YES;
infoLabel.text = @"8: Masked View - effect view hidden";
step = 0;
break;
}
}
@end
评论
0赞
Vulkan
9/5/2022
感谢您的回复。它有效,但我不确定整个演示项目是否必要。我很高兴你解释了你所做的一切,但你可以只使用在阴影视图上添加白色填充蒙版的片段。
评论