我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事

我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。


当前回答

这里是masksToBounds冲突问题的解决方案,它适用于我。

在你设置corderRadius/borderColor/shadow等之后,将masksToBounds设置为NO:

v.layer.masksToBounds = NO;

其他回答

当为容器视图分配阴影路径时,我使用以下技巧解决了这个问题:

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

请注意,阴影的路径是一个圆角矩形,与单元格包含的背景具有相同的角半径:

//this is the border for the UIView that is added to a cell
cell.backgroundView.layer.cornerRadius = 12;
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cell.backgroundView.layer.borderWidth = 1;

//this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
cell.layer.shadowRadius = 2;
cell.layer.cornerRadius = 12;
cell.layer.masksToBounds = NO;
[[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];

[[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
[[cell layer] setShadowOpacity:1.0];

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
[[cell layer] setShadowPath:[path CGPath]];

如果你特别想为uibutton定制圆角,有很多不同的方法来实现。

下面的代码示例(感谢Erica)很好地概述了所有可能性。

iOS 15之前的圆角按钮

在iOS 15之前,你可以通过设置图层来制作圆角按钮。cornerRadius, backgroundColor和setTitleColor。

let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 8

button.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

胶囊按钮

如果我们增加足够大的角半径值,您可以创建一个胶囊风格的按钮。为了创建一个胶囊风格的按钮,我们设置角半径等于按钮高度的一半。由于按钮的高度可能会根据标题大小或布局而变化,我通常为胶囊样式创建一个UIButton子类。

class CapsuleButton: UIButton {
  override func layoutSubviews() {
    super.layoutSubviews()
    let height = bounds.height
    layer.cornerRadius = height/2
  }
}

let capsule = CapsuleButton(type: .system)
capsule.setTitle("Button", for: .normal)
capsule.setTitleColor(.white, for: .normal)
capsule.backgroundColor = .systemPink
capsule.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

光滑的角落

如果你想复制苹果平滑角,你也可以用拐角曲线属性来做。要创建连续的平滑角,请设置图层。按钮连续的曲线。

let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 8
button.layer.cornerCurve = .continuous

button.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

圆角按钮在iOS 15使用UIButton。配置

在iOS 15中,苹果引入了一种通过UIButton.Configuration自定义按钮的新方法。

var configuration = UIButton.Configuration.filled()

configuration.title = "Button"
configuration.baseBackgroundColor = UIColor.systemPink
configuration.contentInsets = NSDirectionalEdgeInsets(
  top: 10,
  leading: 20,
  bottom: 10,
  trailing: 20
)

let button = UIButton(configuration: configuration, primaryAction: nil)

使用cornerStyle控制角的半径

UIButton。配置有许多内置的角样式供您选择。你可以用cornerStyle属性来设置。

configuration.cornerStyle = .small
configuration.cornerStyle = .medium
configuration.cornerStyle = .large
configuration.cornerStyle = .capsule

自定义角半径

如果你想要一些更独特的东西,你可以通过UIBackgroundConfiguration的cornerRadius指定角的半径。

var configuration = UIButton.Configuration.filled()
configuration.title = "Button"
configuration.baseBackgroundColor = UIColor.systemPink
configuration.contentInsets = NSDirectionalEdgeInsets(
  top: 10,
  leading: 20,
  bottom: 10,
  trailing: 20
)
configuration.background.cornerRadius = 20

configuration.cornerStyle = .fixed


let button = UIButton(configuration: configuration, primaryAction: nil)

这里有一个肯定有效的解决方案!

我已经创建了UIView扩展所需的边应用阴影如下


enum AIEdge:Int {
    case
    Top,
    Left,
    Bottom,
    Right,
    Top_Left,
    Top_Right,
    Bottom_Left,
    Bottom_Right,
    All,
    None
}

extension UIView {
        
    func applyShadowWithCornerRadius(color:UIColor, opacity:Float, radius: CGFloat, edge:AIEdge, shadowSpace:CGFloat, cornerRadius: CGFloat)    {

        var sizeOffset:CGSize = CGSize.zero
        
        switch edge {
        case .Top:
            sizeOffset = CGSize(width: 0, height: -shadowSpace)
        case .Left:
            sizeOffset = CGSize(width: -shadowSpace, height: 0)
        case .Bottom:
            sizeOffset = CGSize(width: 0, height: shadowSpace)
        case .Right:
            sizeOffset = CGSize(width: shadowSpace, height: 0)
            
            
        case .Top_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: -shadowSpace)
        case .Top_Right:
            sizeOffset = CGSize(width: shadowSpace, height: -shadowSpace)
        case .Bottom_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: shadowSpace)
        case .Bottom_Right:
            sizeOffset = CGSize(width: shadowSpace, height: shadowSpace)
            
            
        case .All:
            sizeOffset = CGSize(width: 0, height: 0)
        case .None:
            sizeOffset = CGSize.zero
        }

        self.layer.cornerRadius = cornerRadius
        self.layer.masksToBounds = true

        self.layer.shadowColor = color.cgColor
        self.layer.shadowOpacity = opacity
        self.layer.shadowOffset = sizeOffset
        self.layer.shadowRadius = radius
        self.layer.masksToBounds = false

        self.layer.shadowPath = UIBezierPath(roundedRect:self.bounds, cornerRadius:self.layer.cornerRadius).cgPath
    }
}

最后,你可以为你的UIView子类调用下面的阴影函数,你也可以指定边缘上应用阴影,尝试不同的变化根据你需要改变下面方法调用的参数。

viewRoundedToBeShadowedAsWell.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)

注意:如果仍然不工作,试着从主线程调用它

DispatchQueue.main.async {
   viewRoundedToBeShadowedAsWell.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)
}

希望有人觉得这有用!

以下是结果图片:

我对daniel.gindi的代码做了一些修改

这就是你要做的一切。

+ (void)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andBlur:         (CGFloat)blur andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame = view.frame;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.backgroundColor = [UIColor redColor];
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = blur;
    shadow.layer.cornerRadius = view.layer.cornerRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
}
extension UIView {
    func dropRoundedShadowForAllSides() {
        let backgroundView = UIView(frame:self.frame)
        let radius = frame.height/2
        backgroundView.layer.masksToBounds = false
        self.layer.masksToBounds = true
        backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
        backgroundView.layer.shadowRadius = 4
        backgroundView.layer.shadowOpacity = 0.4

        let path = UIBezierPath()

        // Start at the Top Left Corner + radius distance
        path.move(to: CGPoint(x: 2*radius, y: 0.0))

        // Move to the Top Right Corner - radius distance
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width - radius, y: 0.0))

        // Move to top right corner + radius down as curve
        let centerPoint1 = CGPoint(x:backgroundView.frame.size.width - radius,y:radius)
        path.addArc(withCenter: centerPoint1, radius: radius, startAngle: 3*(.pi/2), endAngle: 0, clockwise: true)

        // Move to the Bottom Right Corner - radius
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width, y: backgroundView.frame.size.height - radius))

        // Move to top right corner + radius left as curve
        let centerPoint2 = CGPoint(x:backgroundView.frame.size.width - radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint2, radius: radius, startAngle: 0, endAngle: .pi/2, clockwise: true)

        // Move to the Bottom Left Corner - radius
        path.addLine(to: CGPoint(x: radius, y: backgroundView.frame.size.height))

        // Move to left right corner - radius up as curve
        let centerPoint3 = CGPoint(x:radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint3, radius: radius, startAngle: .pi/2, endAngle: .pi, clockwise: true)

        // Move to the top Left Corner - radius
        path.addLine(to: CGPoint(x: 0, y: radius))

        // Move to top right corner + radius down as curve
        let centerPoint4 = CGPoint(x:radius,y:radius)
        path.addArc(withCenter: centerPoint4, radius: radius, startAngle: .pi, endAngle: 3 * (.pi/2), clockwise: true)

        path.close()

        backgroundView.layer.shadowPath = path.cgPath
        if let superView = self.superview {
            superView.addSubview(backgroundView)
            superView.sendSubview(toBack: backgroundView)
            superView.bringSubview(toFront: self)
        }

    }
}