将 CAShapeLayer 应用于除 UIButton 之外的主 UIView
Posted
技术标签:
【中文标题】将 CAShapeLayer 应用于除 UIButton 之外的主 UIView【英文标题】:Apply CAShapeLayer to main UIView except UIButton 【发布时间】:2016-04-04 13:30:39 【问题描述】:这是一个将掩码应用于整个 UIView 的代码:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
[maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center
radius:self.mapCardsButton.frame.size.height/2.0f
startAngle:0.0f
endAngle:2.0f*M_PI
clockwise:NO]];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.path = maskPath.CGPath;
self.view.layer.mask = maskLayer;
问题是我想将上面的掩码应用于整个 UIView,除了一个特定的 UIButton(mapCardsButton) 也在同一个 UIView 上。 有可能吗?
UPD:我试过了
[self.view.layer insertSublayer:maskLayer atIndex:0];
而不是
self.view.layer.mask = maskLayer;
但我的 self.view 丢失了 alpha 通道,并且 maskLayer 的动画不再起作用
这是一个项目代码:https://www.dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0
【问题讨论】:
[self.view.layer insertSublayer:gradient atIndex:0]; 添加此代码后,我的 UIView 变为黑色,没有 alpha,并且 maskLayer 的动画不再起作用。 所以你想屏蔽全视图,只显示当前显示的完整按钮框架 专家级 你在说什么?请看这张图片imgur.com/6w6mLqm 另一张图片imgur.com/xrgokDV 【参考方案1】:您为什么不尝试以下方法?而不是下面的堆栈:
• 掩码(视图)-> 按钮
在附加的子视图中使视图背景颜色清晰,并执行以下操作:
• 视图 -> 掩码(子视图)、按钮
这样您将获得相同的视觉效果,但使用底部视图作为容器。在代码中:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
[maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center
radius:self.mapCardsButton.frame.size.height/2.0f
startAngle:0.0f
endAngle:2.0f*M_PI
clockwise:NO]];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.path = maskPath.CGPath;
UIView *maskedView = [[UIView alloc] initWithFrame:self.view.bounds];
maskedView.mask = maskLayer;
self.view.backgroundColor = [UIColor clearColor];
[self.view addSubView:maskedView];
[self.view addSubView:self.mapCardsButton];
【讨论】:
【参考方案2】:最简单的方法是让UIButton
成为屏蔽视图的兄弟视图,而不是子视图。我意识到将按钮作为子视图可能是合乎逻辑的(特别是因为看起来您的代码可能来自UIViewController
子类),所以我将创建一个容器UIView
来保存所有其他子视图mapCardsButton
并将遮罩应用到这个新视图。
假设你调用了新视图maskedContainerView
,那么:
self.view
有两个子视图:maskedContainerView
和 mapCardsButton
maskedContainerView
包含 self.view
以前的所有子视图,除了 mapCardsButton
maskedContainerView.layer.mask = maskLayer
。
【讨论】:
感谢您的回复。我尝试了您的解决方案,但仍然无法正常工作。现在它显示 mapCardsButton 但不会产生“洞”。这是一个带有代码的项目:dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0 嘿。抱歉耽搁了。我刚刚看了你的代码。我认为缺少的只是maskedContainerView
应该包含self.view
曾经使用的内容,即maskedContainerView
应该将其背景颜色设置为self.view
当前设置的灰色/蓝色背景颜色。那么self.view
应该是完全透明的; self.view.backgroundColor = [UIColor clearColor]
.
stefandouganhyde,不错的解决方法!我在想那个案子
太棒了!所以它的外观和功能都符合您的预期,@Sergio?【参考方案3】:
[maskedContainerView.layer insertSublayer:maskLayer atIndex:(unsigned)maskedContainerView.layer.sublayers.count];
重要性是 view.layer.sublayers.count 在 'atIndex' 处不是 0
请收下!
【讨论】:
【参考方案4】:基于您的代码。我不确定这是你想要的。
只需将按钮的 UIBezierPath 添加到您的 maskPath。 像这样的代码(基于您的代码)
const NSInteger kHoleSize = 100;
UIButton *mapCardsButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kHoleSize, kHoleSize )];
[mapCardsButton setTitle:@"BUTTON" forState:UIControlStateNormal];
mapCardsButton.backgroundColor = [UIColor redColor];
[self.view addSubview:mapCardsButton];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:self.view.center
radius:kHoleSize/2.0f
startAngle:0.0f
endAngle:2.0f*M_PI
clockwise:NO];
UIBezierPath *buttonPath = [UIBezierPath bezierPathWithRect:mapCardsButton.frame];
[circlePath appendPath:buttonPath];
[maskPath appendPath:circlePath];
[maskPath setUsesEvenOddFillRule:YES];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = maskPath.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.opacity = 0.9;
[self.view.layer addSublayer:maskLayer];
【讨论】:
以上是关于将 CAShapeLayer 应用于除 UIButton 之外的主 UIView的主要内容,如果未能解决你的问题,请参考以下文章
CSS:将 CSS 样式应用于除 Material Angular 之外的所有内容
将border-right应用于除最后一个元素之外的所有元素