梯形蒙版

UIView扩展实现梯形背景

920 发布: 2025/10/16 20:36 本文总阅读量
swift扩展实现梯形背景
// MARK: - 梯形
extension UIView {
    /// 给 View 添加“上长下窄+底部圆角”的梯形蒙版(修正右侧圆角问题)
    /// - Parameters:
    ///   - bottomInset: 下底左右向内缩进的距离(缩进越大,下底越窄)
    ///   - bottomCornerRadius: 底部两个角的圆角半径(≥0,值越大圆角越明显)
    @objc func addTrapezoidMask(with bottomInset: CGFloat, bottomCornerRadius: CGFloat) {
        // 1. 创建蒙版图层
        let maskLayer = CAShapeLayer()
        maskLayer.frame = self.bounds

        // 2. 定义基础坐标(基于 View 的 bounds)
        let width = self.bounds.width
        let height = self.bounds.height

        // 上底:左上角(0,0)、右上角(width,0)(完整宽度,直角)
        let topLeft = CGPoint(x: 0, y: 0)
        let topRight = CGPoint(x: width, y: 0)

        // 下底核心参数:计算下底实际宽度,确保圆角有足够空间
        let bottomTotalWidth = width - 2 * bottomInset
        let safeCornerRadius = min(bottomCornerRadius, bottomTotalWidth / 2) // 圆角不超过下底宽度的一半
        let bottomLeftX = bottomInset
        let bottomRightX = width - bottomInset
        let bottomY = height

        // 3. 定义底部圆角的关键坐标(圆弧的起点和终点)
        // 右侧圆角:从 下底右顶点上方(Y=height - safeCornerRadius)→ 下底右顶点左侧(X=bottomRightX - safeCornerRadius)
        let rightArcStart = CGPoint(x: bottomRightX, y: bottomY - safeCornerRadius)
        // 左侧圆角:从 下底左顶点左侧(X=bottomLeftX + safeCornerRadius)→ 下底左顶点上方(Y=height - safeCornerRadius)
        let leftArcEnd = CGPoint(x: bottomLeftX, y: bottomY - safeCornerRadius)

        // 4. 重新绘制梯形路径(修正圆角逻辑)
        let trapezoidPath = UIBezierPath()

        // 上底:左上角 → 右上角(直线,直角)
        trapezoidPath.move(to: topLeft)
        trapezoidPath.addLine(to: topRight)

        // 右侧:右上角 → 右侧圆角起点(直线,梯形斜边)
        trapezoidPath.addLine(to: rightArcStart)

        // 底部右侧圆角:从 rightArcStart → 下底右顶点左侧(绘制圆弧,逆时针)
        // 圆心:(bottomRightX - safeCornerRadius, bottomY - safeCornerRadius)
        // 半径:safeCornerRadius
        // 起始角度:π/2(下向)→ 结束角度:0(右向)
        trapezoidPath.addArc(
            withCenter: CGPoint(x: bottomRightX - safeCornerRadius, y: bottomY - safeCornerRadius),
            radius: safeCornerRadius,
            startAngle: .pi / 2,
            endAngle: 0,
            clockwise: false // 关键修正:逆时针绘制,确保圆角向外凸起
        )

        // 底部直线:下底右顶点左侧 → 下底左顶点右侧(连接两个圆角)
        let bottomMiddleStart = CGPoint(x: bottomRightX - safeCornerRadius, y: bottomY)
        let bottomMiddleEnd = CGPoint(x: bottomLeftX + safeCornerRadius, y: bottomY)
        trapezoidPath.addLine(to: bottomMiddleStart)
        trapezoidPath.addLine(to: bottomMiddleEnd)

        // 底部左侧圆角:从 bottomMiddleEnd → 左侧圆角终点(绘制圆弧,逆时针)
        // 圆心:(bottomLeftX + safeCornerRadius, bottomY - safeCornerRadius)
        // 半径:safeCornerRadius
        // 起始角度:π(左向)→ 结束角度:π/2(下向)
        trapezoidPath.addArc(
            withCenter: CGPoint(x: bottomLeftX + safeCornerRadius, y: bottomY - safeCornerRadius),
            radius: safeCornerRadius,
            startAngle: .pi,
            endAngle: .pi / 2,
            clockwise: false // 逆时针绘制,与右侧圆角对称
        )

        // 左侧:左侧圆角终点 → 左上角(直线,梯形斜边)
        trapezoidPath.addLine(to: leftArcEnd)
        trapezoidPath.addLine(to: topLeft)

        // 闭合路径(确保形状完整)
        trapezoidPath.close()

        // 5. 将路径设置为蒙版,绑定到 View 图层
        maskLayer.path = trapezoidPath.cgPath
        self.layer.mask = maskLayer

        // 开启边界裁剪,确保蒙版生效
        self.layer.masksToBounds = true
    }
}