You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何创建带侧边凸起的自定义RoundedRectangle Shape?

实现侧边带凸起的自定义圆角矩形形状

下面是用SwiftUI实现该自定义形状的代码,核心是通过自定义Path拼接基础圆角矩形和侧边凸起的路径:

import SwiftUI

struct BumpedRoundedRectangle: Shape {
    // 基础圆角半径
    var cornerRadius: CGFloat
    // 凸起向外延伸的横向长度
    var bumpWidth: CGFloat
    // 凸起的垂直高度(对应半圆直径)
    var bumpHeight: CGFloat
    // 凸起位置:0为左侧,1为右侧
    var bumpSide: CGFloat = 1.0
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        
        // 计算凸起的垂直中心坐标
        let bumpCenterY = rect.midY
        let halfBumpHeight = bumpHeight / 2
        
        // 开始绘制基础圆角矩形路径
        path.move(to: CGPoint(x: rect.minX, y: rect.minY + cornerRadius))
        
        // 左上角圆角
        path.addArc(center: CGPoint(x: rect.minX + cornerRadius, y: rect.minY + cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(180),
                    endAngle: .degrees(270),
                    clockwise: false)
        
        // 顶部边(到凸起前的位置)
        let topEdgeEndX = bumpSide < 0.5 ? rect.minX + cornerRadius : rect.maxX - cornerRadius - bumpWidth
        path.addLine(to: CGPoint(x: topEdgeEndX, y: rect.minY))
        
        // 绘制右侧凸起
        if bumpSide >= 0.5 {
            path.addLine(to: CGPoint(x: rect.maxX - bumpWidth, y: bumpCenterY - halfBumpHeight))
            // 凸起半圆
            path.addArc(center: CGPoint(x: rect.maxX, y: bumpCenterY),
                        radius: halfBumpHeight,
                        startAngle: .degrees(180),
                        endAngle: .degrees(0),
                        clockwise: false)
            path.addLine(to: CGPoint(x: rect.maxX - bumpWidth, y: bumpCenterY + halfBumpHeight))
            path.addLine(to: CGPoint(x: rect.maxX - bumpWidth, y: rect.maxY))
        } else {
            // 绘制左侧凸起
            path.addLine(to: CGPoint(x: rect.minX + bumpWidth, y: bumpCenterY - halfBumpHeight))
            // 凸起半圆
            path.addArc(center: CGPoint(x: rect.minX, y: bumpCenterY),
                        radius: halfBumpHeight,
                        startAngle: .degrees(0),
                        endAngle: .degrees(180),
                        clockwise: false)
            path.addLine(to: CGPoint(x: rect.minX + bumpWidth, y: bumpCenterY + halfBumpHeight))
            path.addLine(to: CGPoint(x: rect.minX + bumpWidth, y: rect.maxY))
        }
        
        // 右下角圆角
        path.addArc(center: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(90),
                    endAngle: .degrees(0),
                    clockwise: false)
        
        // 底部边
        let bottomEdgeStartX = bumpSide < 0.5 ? rect.minX + cornerRadius + bumpWidth : rect.minX + cornerRadius
        path.addLine(to: CGPoint(x: bottomEdgeStartX, y: rect.maxY))
        
        // 左下角圆角
        path.addArc(center: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(0),
                    endAngle: .degrees(90),
                    clockwise: false)
        
        // 左侧边回到起点
        path.addLine(to: CGPoint(x: rect.minX, y: rect.minY + cornerRadius))
        
        return path
    }
    
    // 支持参数动画
    var animatableData: AnimatablePair<AnimatablePair<CGFloat, CGFloat>, AnimatablePair<CGFloat, CGFloat>> {
        get {
            AnimatablePair(AnimatablePair(cornerRadius, bumpWidth), AnimatablePair(bumpHeight, bumpSide))
        }
        set {
            cornerRadius = newValue.first.first
            bumpWidth = newValue.first.second
            bumpHeight = newValue.second.first
            bumpSide = newValue.second.second
        }
    }
}

// 使用示例
struct BumpedRectangleDemo: View {
    var body: some View {
        BumpedRoundedRectangle(cornerRadius: 16, bumpWidth: 20, bumpHeight: 40)
            .fill(Color.blue)
            .frame(width: 200, height: 120)
            .padding()
    }
}

#Preview {
    BumpedRectangleDemo()
}

参数说明

  • cornerRadius: 基础圆角矩形的圆角半径
  • bumpWidth: 凸起向外延伸的横向长度
  • bumpHeight: 凸起的垂直高度
  • bumpSide: 控制凸起位置,0对应左侧,1对应右侧

你可以根据需求调整这些参数匹配目标形状,若需要凸起为圆角矩形而非半圆,只需将addArc部分替换为对应的圆角矩形路径即可。

内容的提问来源于stack exchange,提问作者Rebin A. Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 20:46:12