【问题标题】:Round specific corners of and show shadow on specific sides only圆特定角并仅在特定侧面显示阴影
【发布时间】:2023-09-20 21:16:01
【问题描述】:

我有以下代码可以只圆视图的特定角:

- (void)roundOnlySpecifiedCornersInView:(UIView *)view corners:(UIRectCorner)corners
{
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:(corners) cornerRadii:CGSizeMake(4.0, 4.0)];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

    maskLayer.path  = maskPath.CGPath;
    view.layer.mask = maskLayer;
}

这可以完美地隔离。现在我也想在我的视图中使用阴影,但我特别想在不同的情况下应用阴影:

  • 四面八方
  • 除底部外的所有侧面
  • 除顶部外的所有侧面
  • 仅限左侧/右侧

我遇到的所有技术都是通过创建视图的插图来工作的。问题在于,假设您只想在左侧/右侧保留阴影,您会偏移底部和顶部。由于 Rect 现在不那么高了,左右的阴影不会覆盖视图的整个高度。此外,用于圆角的遮罩层会导致阴影不再出现。

示例代码:

    innerView.layer.shadowColor = [[UIColor colorWithWhite:0.0f alpha:0.1f] CGColor];
    innerView.layer.shadowOpacity = 1.0f;
    innerView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
    innerView.layer.shadowRadius = 6.0f;

    CGRect shadowFrame = UIEdgeInsetsInsetRect(innerView.bounds, UIEdgeInsetsMake(9, 0, 9, 0));
    CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;

    innerView.layer.shadowPath = shadowPath;

如何将视图中的特定角弄圆,同时仅在指定边显示阴影?

Swift 中的答案也很受欢迎!

我想要的屏幕截图(这个很简单,因为所有角都需要圆角,所以我可以使用.layer.cornerRadius,而且它的四面都有阴影):

现在我只想圆化两个角(左上角和右上角,左下角和右下角),并且只在某些边上添加阴影。

【问题讨论】:

  • 你能展示你拥有/想要的东西的截图吗?
  • @KiritModi 你指的是我已经拥有的用于圆角的完全相同的代码。
  • @jtbandes 截图已添加。

标签: ios objective-c uiview uibezierpath


【解决方案1】:

我不确定它是否符合您的要求。代码创建一个带有顶部和底部阴影的图像,以及所有圆角,您可以修改代码以实现您所需要的。你可以把图片作为你单元格的背景(好像是UITableViewCell

如果它不适合你,请告诉我。

图片:

// create a shadow image
CGSize size = CGSizeMake(ScreenWidth, ScreenWidth);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();

UIColor *backgroundColor = [UIColor colorWithRed:246.0/255.0 green:246.0/255.0 blue:246.0/255.0 alpha:1.0];
UIColor *fillColor = [UIColor whiteColor];
CGRect rect = CGRectMake(10, 10, 100, 44);

// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));

// set top and bottom shadow
CGRect rectTop = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, -5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectTop);
CGContextRestoreGState(context);

CGRect rectBottom = CGRectMake(rect.origin.x, rect.origin.y+rect.size.height-5, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, 5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectBottom);
CGContextRestoreGState(context);

// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, rect);

CGContextSaveGState(context);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(4.0, 4.0)];
[maskPath addClip];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillRect(context, rect);
CGContextRestoreGState(context);

您可以修改代码以获得左上阴影:

// create a shadow image
CGSize size = CGSizeMake(ScreenWidth, ScreenWidth);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();

UIColor *backgroundColor = [UIColor colorWithRed:246.0/255.0 green:246.0/255.0 blue:246.0/255.0 alpha:1.0];
UIColor *fillColor = [UIColor whiteColor];
CGRect rect = CGRectMake(10, 10, 100, 44);

// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));

// set top and left shadow
CGRect rectTop = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, 5);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, -5), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectTop);
CGContextRestoreGState(context);

CGRect rectLeft = CGRectMake(rect.origin.x, rect.origin.y, 5, rect.size.height);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(-5, 0), 5, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rectLeft);
CGContextRestoreGState(context);

// re-draw the background
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, rect);

CGContextSaveGState(context);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(4.0, 4.0)];
[maskPath addClip];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillRect(context, rect);
CGContextRestoreGState(context);

HTH

【讨论】:

  • 感谢您的回答。对于阴影,我只是想念在左右两边添加阴影,但我想我可以从你的回答中得出。
【解决方案2】:

当然,在很多很多情况下,您都希望通过绘制阴影来实现这一点。但是,您可以考虑以下方法:使用可拉伸图像,阴影恰好位于您需要的侧面,例如类似的东西(这个虽然四面都有阴影):

在您说:“Ewwwww!他使用图像来制作简单的阴影!”之前,让我强调一下,这在性能方面会更好。例如,如果您在 UICollectionView 中有很多单元格,并且每个单元格都在重新绘制其阴影,则它可能会在滚动期间显着减慢您的应用程序,而基于图像的阴影将基本相同。

我会更进一步,建议您实际上可以使用可拉伸图像来用圆角遮盖视图!现在,这可能看起来有点过头了,但如果你注意到性能急剧下降,我会试一试。您基本上需要做的是准备另一个具有透明“中间”部分和与背景颜色相同的圆角的可拉伸图像。比如:

再一次,在你否决这种奇怪的方式之前,可以通过两行代码轻松实现......

view.layer.cornerRadius = 20
view.layer.masksToBounds = true

...让我指出,当您必须同时显示一堆蒙版视图时,这将非常荒谬地工作:例如,屏蔽UICollectionViewCells。基本上,如果您在UIView 的图层上设置蒙版,则该蒙版将被重新计算并实时应用,这会在频繁重绘UIView 内容期间在性能方面花费很多— 例如,当滚动 UITableViewUICollectionView 时。

显然,如果您的背景不是纯色并且具有渐变,那么这将不起作用。但是,在许多其他情况下,这可能会帮助您实现更流畅的 UI 性能。在您的特定情况下的另一个优势是您可以轻松控制要遮盖的角以及阴影应该落在哪里。

再次重申,我并不是在暗示这是适用于每种情况的方法。我要说的是,在很多情况下,这可以帮助显着提高性能:例如,如果您屏蔽了太多同时呈现在屏幕上的视图,并且布局预计将经常重绘。

【讨论】:

    【解决方案3】:

    为特定的拐角设置拐角半径

    参考来自:how to set cornerRadius for only top-left and top-right corner of a UIView?

    UIBezierPath *maskPath;
    maskPath = [UIBezierPathbezierPathWithRoundedRect:_backgroundImageView.bounds 
                                 byRoundingCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight) 
                                       cornerRadii:CGSizeMake(3.0, 3.0)];
    
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame = self.bounds;
    maskLayer.path = maskPath.CGPath;
    _imageView.layer.mask = maskLayer;
    [maskLayer release];
    

    【讨论】:

    • 您的代码与我在开篇文章中给出的代码几乎相同(相同的块)
    最近更新 更多