wake-ios/wake/View/Blind/Box4.swift
2025-08-22 18:58:08 +08:00

140 lines
4.3 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
// MARK: -
struct FilmStripBlindBoxView: View {
@State private var isAnimating = false
@State private var revealCenter = false
// 使 SF Symbols
let boxContents = ["popcorn", "star", "music.note"]
var body: some View {
GeometryReader { geometry in
let width = geometry.size.width
ZStack {
//
BlindBoxFrame(symbol: boxContents[0])
.offset(x: isAnimating ? -width / 4 : -width)
.opacity(isAnimating ? 1 : 0)
//
BlindBoxFrame(symbol: boxContents[1])
.scaleEffect(revealCenter ? 1.6 : 1)
.offset(x: isAnimating ? 0 : width)
.opacity(isAnimating ? 1 : 0)
//
BlindBoxFrame(symbol: boxContents[2])
.offset(x: isAnimating ? width / 4 : width * 1.5)
.opacity(isAnimating ? 1 : 0)
}
.onAppear {
//
withAnimation(.easeOut(duration: 1.0)) {
isAnimating = true
}
//
DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) {
withAnimation(
.interpolatingSpring(stiffness: 80, damping: 12).delay(0.3)
) {
revealCenter = true
}
}
}
}
.frame(height: 140)
.padding()
.background(Color.black.opacity(0.05))
}
}
// MARK: - + + SF Symbol
struct BlindBoxFrame: View {
let symbol: String
var body: some View {
ZStack {
// +
FilmBorder()
// SF Symbol
Image(systemName: symbol)
.resizable()
.scaledToFit()
.foregroundColor(.white.opacity(0.85))
.frame(width: 60, height: 60)
}
.frame(width: 120, height: 120)
}
}
// MARK: - #FFB645 +
struct FilmBorder: View {
var body: some View {
Canvas { context, size in
let w = size.width
let h = size.height
// FFB645
let bgColor = Color(hex: 0xFFB645)
context.fill(Path(CGRect(origin: .zero, size: size)), with: .color(bgColor))
//
let holeRadius: CGFloat = 3.5
let margin: CGFloat = 12
let holeYOffset: CGFloat = h * 0.25
// 3
for i in 0..<3 {
let y = CGFloat(i + 1) * (h / 4)
context.fill(
Path(ellipseIn: CGRect(
x: margin - holeRadius * 2,
y: y - holeRadius,
width: holeRadius * 2,
height: holeRadius * 2
)),
with: .color(.black)
)
}
// 3
for i in 0..<3 {
let y = CGFloat(i + 1) * (h / 4)
context.fill(
Path(ellipseIn: CGRect(
x: w - margin,
y: y - holeRadius,
width: holeRadius * 2,
height: holeRadius * 2
)),
with: .color(.black)
)
}
}
}
}
// MARK: - Color HEX
extension Color {
init(hex: UInt) {
self.init(
.sRGB,
red: Double((hex >> 16) & 0xff) / 255,
green: Double((hex >> 8) & 0xff) / 255,
blue: Double(hex & 0xff) / 255,
opacity: 1.0
)
}
}
// MARK: -
struct FilmStripBlindBoxView_Previews: PreviewProvider {
static var previews: some View {
FilmStripBlindBoxView()
.preferredColorScheme(.dark)
}
}