From ecc
Apple의 Liquid Glass 구현 패턴입니다. Liquid Glass는 뒤에 있는 콘텐츠를 흐리게 처리(blur)하고, 주변 콘텐츠의 색상과 빛을 반사하며, 터치 및 포인터 상호작용에 반응하는 동적 머티리얼(material)입니다. SwiftUI, UIKit 및 WidgetKit 통합 방법을 다룹니다.
npx claudepluginhub sam42-lab/everything-claude-code-krThis skill uses the workspace's default tool permissions.
Apple의 Liquid Glass 구현 패턴입니다. Liquid Glass는 뒤에 있는 콘텐츠를 흐리게 처리(blur)하고, 주변 콘텐츠의 색상과 빛을 반사하며, 터치 및 포인터 상호작용에 반응하는 동적 머티리얼(material)입니다. SwiftUI, UIKit 및 WidgetKit 통합 방법을 다룹니다.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Apple의 Liquid Glass 구현 패턴입니다. Liquid Glass는 뒤에 있는 콘텐츠를 흐리게 처리(blur)하고, 주변 콘텐츠의 색상과 빛을 반사하며, 터치 및 포인터 상호작용에 반응하는 동적 머티리얼(material)입니다. SwiftUI, UIKit 및 WidgetKit 통합 방법을 다룹니다.
어떤 뷰에든 Liquid Glass를 추가하는 가장 간단한 방법:
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect() // 기본값: regular 변형, 캡슐 모양
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16.0))
주요 사용자 정의 옵션:
.regular — 표준 유리 효과.tint(Color) — 강조를 위해 색상 틴트 추가.interactive() — 터치 및 포인터 상호작용에 반응.capsule (기본값), .rect(cornerRadius:), .circleButton("Click Me") { /* 액션 */ }
.buttonStyle(.glass)
Button("Important") { /* 액션 */ }
.buttonStyle(.glassProminent)
성능 및 모핑을 위해 항상 여러 유리 뷰를 컨테이너로 감싸세요:
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
}
}
spacing 파라미터는 병합 거리를 제어합니다 — 요소들이 가까워질수록 유리 모양이 함께 섞입니다.
glassEffectUnion을 사용하여 여러 뷰를 단일 유리 모양으로 결합하세요:
@Namespace private var namespace
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
ForEach(symbolSet.indices, id: \.self) { item in
Image(systemName: symbolSet[item])
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace)
}
}
}
유리 요소가 나타나거나 사라질 때 매끄러운 모핑 효과를 생성하세요:
@State private var isExpanded = false
@Namespace private var namespace
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("pencil", in: namespace)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("eraser", in: namespace)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
가로 스크롤 콘텐츠가 사이드바나 인스펙터 아래로 확장되도록 하려면, ScrollView 콘텐츠가 컨테이너의 리딩/트레일링 가장자리에 닿도록 하세요. 레이아웃이 가장자리까지 확장되면 시스템이 사이드바 아래 스크롤 동작을 자동으로 처리하므로 추가적인 수정자는 필요하지 않습니다.
let glassEffect = UIGlassEffect()
glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3)
glassEffect.isInteractive = true
let visualEffectView = UIVisualEffectView(effect: glassEffect)
visualEffectView.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.layer.cornerRadius = 20
visualEffectView.clipsToBounds = true
view.addSubview(visualEffectView)
NSLayoutConstraint.activate([
visualEffectView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
visualEffectView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
visualEffectView.widthAnchor.constraint(equalToConstant: 200),
visualEffectView.heightAnchor.constraint(equalToConstant: 120)
])
// contentView에 콘텐츠 추가
let label = UILabel()
label.text = "Liquid Glass"
label.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.contentView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: visualEffectView.contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: visualEffectView.contentView.centerYAnchor)
])
let containerEffect = UIGlassContainerEffect()
containerEffect.spacing = 40.0
let containerView = UIVisualEffectView(effect: containerEffect)
let firstGlass = UIVisualEffectView(effect: UIGlassEffect())
let secondGlass = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(firstGlass)
containerView.contentView.addSubview(secondGlass)
scrollView.topEdgeEffect.style = .automatic
scrollView.bottomEdgeEffect.style = .hard
scrollView.leftEdgeEffect.isHidden = true
let favoriteButton = UIBarButtonItem(image: UIImage(systemName: "heart"), style: .plain, target: self, action: #selector(favoriteAction))
favoriteButton.hidesSharedBackground = true // 공유 유리 배경에서 제외
struct MyWidgetView: View {
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
if renderingMode == .accented {
// 강조(Accented) 모드: 흰색 틴트가 적용된 테마 유리 배경
} else {
// 풀 컬러 모드: 표준 모양
}
}
}
HStack {
VStack(alignment: .leading) {
Text("Title")
.widgetAccentable() // 강조 그룹
Text("Subtitle")
// 기본 그룹
}
Image(systemName: "star.fill")
.widgetAccentable() // 강조 그룹
}
Image("myImage")
.widgetAccentedRenderingMode(.monochrome)
VStack { /* 콘텐츠 */ }
.containerBackground(for: .widget) {
Color.blue.opacity(0.2)
}
| 결정 사항 | 근거 |
|---|---|
| GlassEffectContainer 래핑 | 성능 최적화, 유리 요소 간 모핑 가능 |
spacing 파라미터 | 병합 거리 제어 — 요소들이 얼마나 가까워야 섞일지 미세 조정 |
@Namespace + glassEffectID | 뷰 계층 구조 변경 시 매끄러운 모핑 전환 가능 |
interactive() 수정자 | 터치/포인터 반응에 명시적으로 참여 — 모든 유리가 반응할 필요는 없음 |
| UIKit의 UIGlassContainerEffect | 일관성을 위해 SwiftUI와 동일한 컨테이너 패턴 적용 |
| 위젯의 강조 렌더링 모드 | 사용자가 강조된 홈 화면을 선택할 때 시스템이 틴트 유리 적용 |
.glassEffect()는 다른 모양 수정자(frame, font, padding) 다음에 적용하세요..interactive()는 사용자 상호작용에 응답하는 요소(버튼, 토글 항목 등)에만 사용하세요.withAnimation을 사용하세요. 매끄러운 모핑 전환이 가능해집니다..glassEffect() 뷰 사용clipsToBounds = true 누락