IOS-封装了一个好用的给view阴影圆角边框的控件ShadowView

import UIKit
 
@IBDesignable
class ShadowView: UIView {
    
    // MARK: - 背景色优化(核心修改点)
       override var backgroundColor: UIColor? {
           didSet {
               // 当外部设置背景色时,优先使用自定义值
               if backgroundColor != nil {
                   layer.backgroundColor  = backgroundColor?.cgColor
               } else {
                   // 未设置时使用默认白色
                   layer.backgroundColor  = UIColor.white.cgColor
               }
           }
       }
    
    // MARK: - 阴影属性
    @IBInspectable var shadowColor: UIColor = .black.withAlphaComponent(0.3)  {
        didSet { layer.shadowColor  = shadowColor.cgColor  }
    }
    
    @IBInspectable var shadowOpacity: Float = 0.5 {
        didSet { layer.shadowOpacity  = shadowOpacity }
    }
    
    @IBInspectable var shadowOffset: CGSize = CGSize(width: 0, height: 2) {
        didSet { layer.shadowOffset  = shadowOffset }
    }
    
    @IBInspectable var shadowRadius: CGFloat = 4 {
        didSet {
            layer.shadowRadius  = shadowRadius
            setNeedsShadowPathUpdate()
        }
    }
    
    // MARK: - 圆角属性
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            if !hasCustomRadius {
                layer.cornerRadius  = cornerRadius
                setNeedsShadowPathUpdate()
            }
        }
    }
    
    // 独立圆角控制
    @IBInspectable var topLeftRadius: CGFloat = 0 {
        didSet { setNeedsCornerMaskUpdate() }
    }
    
    @IBInspectable var topRightRadius: CGFloat = 0 {
        didSet { setNeedsCornerMaskUpdate() }
    }
    
    @IBInspectable var bottomLeftRadius: CGFloat = 0 {
        didSet { setNeedsCornerMaskUpdate() }
    }
    
    @IBInspectable var bottomRightRadius: CGFloat = 0 {
        didSet { setNeedsCornerMaskUpdate() }
    }
    
    // MARK: - 边框属性
    @IBInspectable var borderColor: UIColor = .clear {
        didSet { layer.borderColor  = borderColor.cgColor  }
    }
    
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet { layer.borderWidth  = borderWidth }
    }
    
    // MARK: - 私有属性
    private var needsShadowPathUpdate = true
    private var cornerMaskLayer: CAShapeLayer?
    
    // MARK: - 初始化
    override init(frame: CGRect) {
        super.init(frame:  frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder:  coder)
        commonInit()
    }
    
    private func commonInit() {
        layer.masksToBounds  = false
        // 初始化时强制设置默认背景色
                if backgroundColor == nil {
                    layer.backgroundColor  = UIColor.white.cgColor
                }
        updateCornerMask()
        updateShadowPath()
    }
    
    // MARK: - 布局更新
    override func layoutSubviews() {
        super.layoutSubviews()
        if needsShadowPathUpdate {
            updateShadowPath()
            needsShadowPathUpdate = false
        }
        updateCornerMask()
    }
    
    // MARK: - 圆角处理
    private var hasCustomRadius: Bool {
        [topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius].contains { $0 > 0 }
    }
    
    private func setNeedsCornerMaskUpdate() {
        updateCornerMask()
        setNeedsShadowPathUpdate()
    }
    
    private func updateCornerMask() {
        guard hasCustomRadius else {
            cornerMaskLayer = nil
            layer.mask  = nil
            layer.cornerRadius  = cornerRadius
            return
        }
        
        let path = UIBezierPath(
            roundedRect: bounds,
            topLeftRadius: topLeftRadius,
            topRightRadius: topRightRadius,
            bottomLeftRadius: bottomLeftRadius,
            bottomRightRadius: bottomRightRadius
        )
        
        let maskLayer = cornerMaskLayer ?? CAShapeLayer()
        maskLayer.path  = path.cgPath
        layer.mask  = maskLayer
        cornerMaskLayer = maskLayer
    }
    
    // MARK: - 阴影路径优化
    private func setNeedsShadowPathUpdate() {
        needsShadowPathUpdate = true
        setNeedsLayout()
    }
    
    private func updateShadowPath() {
        guard !bounds.isEmpty  else { return }
        
        let shadowSpread = shadowRadius * 1.5
        let shadowRect = bounds.insetBy(dx:  -shadowSpread, dy: -shadowSpread)
        
        let path: UIBezierPath
        if hasCustomRadius {
            path = UIBezierPath(
                roundedRect: shadowRect,
                topLeftRadius: topLeftRadius + shadowSpread,
                topRightRadius: topRightRadius + shadowSpread,
                bottomLeftRadius: bottomLeftRadius + shadowSpread,
                bottomRightRadius: bottomRightRadius + shadowSpread
            )
        } else {
            path = UIBezierPath(roundedRect: shadowRect, cornerRadius: cornerRadius + shadowSpread)
        }
        
        layer.shadowPath  = path.cgPath
    }
    
    // MARK: - 暗黑模式适配
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.hasDifferentColorAppearance(comparedTo:  previousTraitCollection) {
            adjustShadowForCurrentTheme()
        }
    }
    
    private func adjustShadowForCurrentTheme() {
        let isDarkMode = traitCollection.userInterfaceStyle  == .dark
        shadowOpacity = isDarkMode ? min(0.8, shadowOpacity * 1.2) : max(0.3, shadowOpacity * 0.8)
    }
}
 
// MARK: - UIBezierPath扩展
private extension UIBezierPath {
    convenience init(
        roundedRect rect: CGRect,
        topLeftRadius: CGFloat,
        topRightRadius: CGFloat,
        bottomLeftRadius: CGFloat,
        bottomRightRadius: CGFloat
    ) {
        self.init()
        
        let width = rect.width
        let height = rect.height
        
        // 确保圆角不超过视图尺寸的一半
        let minSide = min(width, height) / 2
        let tl = min(topLeftRadius, minSide)
        let tr = min(topRightRadius, minSide)
        let bl = min(bottomLeftRadius, minSide)
        let br = min(bottomRightRadius, minSide)
        
        move(to: CGPoint(x: tl, y: 0))
        addLine(to: CGPoint(x: width - tr, y: 0))
        addArc(
            withCenter: CGPoint(x: width - tr, y: tr),
            radius: tr,
            startAngle: -.pi / 2,
            endAngle: 0,
            clockwise: true
        )
        
        addLine(to: CGPoint(x: width, y: height - br))
        addArc(
            withCenter: CGPoint(x: width - br, y: height - br),
            radius: br,
            startAngle: 0,
            endAngle: .pi / 2,
            clockwise: true
        )
        
        addLine(to: CGPoint(x: bl, y: height))
        addArc(
            withCenter: CGPoint(x: bl, y: height - bl),
            radius: bl,
            startAngle: .pi / 2,
            endAngle: .pi,
            clockwise: true
        )
        
        addLine(to: CGPoint(x: 0, y: tl))
        addArc(
            withCenter: CGPoint(x: tl, y: tl),
            radius: tl,
            startAngle: .pi,
            endAngle: -.pi / 2,
            clockwise: true
        )
        
        close()
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容