wake-ios/wake/SharedUI/Graphics/ScoopRoundedRect.swift

110 lines
4.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
///
struct ScoopRoundedRect: Shape {
var cornerRadius: CGFloat = 20
/// >0 <0
var scoopDepth: CGFloat = 10
///
var scoopHalfWidth: CGFloat = 18
/// 0~10.5
var scoopCenterX: CGFloat = 0.33
/// false notch
var convexDown: Bool = true
/// /0
var flatHalfWidth: CGFloat = 8
func path(in rect: CGRect) -> Path {
let r = min(cornerRadius, min(rect.width, rect.height) * 0.5)
let topY = rect.minY
// 穿
let minX = rect.minX + r
let maxX = rect.maxX - r
let centerX = rect.minX + rect.width * scoopCenterX
let hw = min(scoopHalfWidth, (maxX - minX) * 0.45)
let flatHW = max(0, min(flatHalfWidth, hw * 0.8))
let shoulder = max(1, hw - flatHW) // 线
let startX = max(minX, centerX - (flatHW + shoulder))
let endX = min(maxX, centerX + (flatHW + shoulder))
let leftFlatX = max(minX, centerX - flatHW)
let rightFlatX = min(maxX, centerX + flatHW)
let depth = (convexDown ? 1 : -1) * scoopDepth
// 线P0 -> Lf线Rf -> P3Lf~Rf 线
let P0 = CGPoint(x: startX, y: topY)
let Lf = CGPoint(x: leftFlatX, y: topY + depth)
let Rf = CGPoint(x: rightFlatX, y: topY + depth)
let P3 = CGPoint(x: endX, y: topY)
// 使 shoulder
let k = shoulder * 0.5522847498
let C1 = CGPoint(x: P0.x + k, y: P0.y) // P0 线
let C2 = CGPoint(x: Lf.x - k, y: Lf.y) // Lf 线
let C3 = CGPoint(x: Rf.x + k, y: Rf.y) // Rf 线
let C4 = CGPoint(x: P3.x - k, y: P3.y) // P3 线
var p = Path()
//
p.move(to: CGPoint(x: rect.minX + r, y: topY))
// 线/
p.addLine(to: P0)
// 线
p.addCurve(to: Lf, control1: C1, control2: C2)
// 线
p.addLine(to: Rf)
// 线
p.addCurve(to: P3, control1: C3, control2: C4)
//
p.addLine(to: CGPoint(x: rect.maxX - r, y: topY))
//
p.addQuadCurve(to: CGPoint(x: rect.maxX, y: rect.minY + r),
control: CGPoint(x: rect.maxX, y: rect.minY))
// 线
p.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - r))
//
p.addQuadCurve(to: CGPoint(x: rect.maxX - r, y: rect.maxY),
control: CGPoint(x: rect.maxX, y: rect.maxY))
//
p.addLine(to: CGPoint(x: rect.minX + r, y: rect.maxY))
//
p.addQuadCurve(to: CGPoint(x: rect.minX, y: rect.maxY - r),
control: CGPoint(x: rect.minX, y: rect.maxY))
//
p.addLine(to: CGPoint(x: rect.minX, y: rect.minY + r))
//
p.addQuadCurve(to: CGPoint(x: rect.minX + r, y: rect.minY),
control: CGPoint(x: rect.minX, y: rect.minY))
p.closeSubpath()
return p
}
}
struct ScoopRoundedRect_Previews: PreviewProvider {
static var previews: some View {
VStack(spacing: 30) {
//
ScoopRoundedRect(cornerRadius: 24, scoopDepth: 8, scoopHalfWidth: 26, scoopCenterX: 0.25, convexDown: true, flatHalfWidth: 12)
.fill(Color.orange)
.frame(height: 140)
.shadow(color: .black.opacity(0.08), radius: 12, y: 6)
.padding()
//
ScoopRoundedRect(cornerRadius: 28, scoopDepth: 12, scoopHalfWidth: 36, scoopCenterX: 0.5, convexDown: true, flatHalfWidth: 18)
.fill(Color.orange)
.frame(height: 140)
.shadow(color: .black.opacity(0.08), radius: 12, y: 6)
.padding()
// notch
ScoopRoundedRect(cornerRadius: 24, scoopDepth: 10, scoopHalfWidth: 22, scoopCenterX: 0.6, convexDown: false, flatHalfWidth: 10)
.fill(Color.orange)
.frame(height: 140)
.shadow(color: .black.opacity(0.08), radius: 12, y: 6)
.padding()
}
.background(Color(white: 0.96))
.previewLayout(.sizeThatFits)
}
}