apple-hig-designer by jamesrochabrun/skills
npx skills add https://github.com/jamesrochabrun/skills --skill apple-hig-designer遵循苹果人机界面指南(HIG)设计美观、原生的 iOS 应用。使用原生组件、恰当的排版、语义化色彩和苹果设计原则,创建无障碍、直观的界面。
帮助你设计和构建感觉原生且遵循苹果指南的 iOS 应用:
使内容清晰且重点突出。
文字在任何尺寸下都清晰易读,图标精确且清晰,装饰元素微妙且恰当,对功能性的关注驱动着设计。
// ✅ 清晰、重点突出的内容
Text("Welcome back, Sarah")
.font(.title)
.foregroundColor(.primary)
// ❌ 不清晰、杂乱
Text("Welcome back, Sarah!!!")
.font(.title)
.foregroundColor(.red)
.background(.yellow)
.overlay(Image(systemName: "star.fill"))
用户界面帮助人们理解和交互内容,但绝不与之竞争。
界面尊重内容,采用轻量的视觉处理,将焦点保持在内容上,并给内容留出呼吸空间。
// ✅ 以内容为中心
VStack(alignment: .leading, spacing: 8) {
Text("Article Title")
.font(.headline)
Text("Article content goes here...")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
// ❌ 分散注意力的 UI
VStack(spacing: 8) {
Text("Article Title")
.font(.headline)
.foregroundColor(.white)
.background(.blue)
.border(.red, width: 3)
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
视觉层次和逼真的动效传达层级关系,帮助人们理解关联。
鲜明的视觉层次和逼真的动效赋予活力并促进理解。触摸和可发现性增强了愉悦感,并能在不丢失上下文的情况下访问功能。
// ✅ 清晰的深度层级
ZStack {
Color(.systemBackground)
VStack {
// 带有高度的卡片
CardView()
.shadow(radius: 8)
}
}
// 使用模糊效果表现深度
Text("Content")
.background(.ultraThinMaterial)
用于导航和操作的顶部栏。
NavigationStack {
List {
Text("Item 1")
Text("Item 2")
}
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Add") {
// Action
}
}
}
}
指南:
用于顶级目的地的底部导航。
TabView {
HomeView()
.tabItem {
Label("Home", systemImage: "house")
}
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
ProfileView()
.tabItem {
Label("Profile", systemImage: "person")
}
}
指南:
可滚动的项目列表。
List {
Section("Today") {
ForEach(items) { item in
NavigationLink {
DetailView(item: item)
} label: {
HStack {
Image(systemName: item.icon)
.foregroundColor(.accentColor)
Text(item.title)
}
}
}
}
}
.listStyle(.insetGrouped)
列表样式:
.plain - 边缘到边缘的行.insetGrouped - 圆角、内嵌的分组(iOS 默认).sidebar - 用于导航侧边栏以模态方式呈现内容。
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Show Details") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
DetailView()
.presentationDetents([.medium, .large])
}
}
}
表单高度:
.medium - 半屏.large - 全屏主要操作控件。
// 填充按钮(主要操作)
Button("Continue") {
// Action
}
.buttonStyle(.borderedProminent)
// 边框按钮(次要操作)
Button("Cancel") {
// Action
}
.buttonStyle(.bordered)
// 纯文本按钮(三级操作)
Button("Learn More") {
// Action
}
.buttonStyle(.plain)
按钮层级:
指南:
文本输入控件。
@State private var username = ""
@State private var password = ""
VStack(alignment: .leading, spacing: 16) {
// 标准文本字段
TextField("Username", text: $username)
.textFieldStyle(.roundedBorder)
.textContentType(.username)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
// 安全字段
SecureField("Password", text: $password)
.textFieldStyle(.roundedBorder)
.textContentType(.password)
}
文本内容类型:
.username - 用户名字段.password - 密码字段.emailAddress - 电子邮件字段.telephoneNumber - 电话号码.creditCardNumber - 信用卡号布尔控件(开关)。
@State private var isEnabled = false
Toggle("Enable notifications", isOn: $isEnabled)
.toggleStyle(.switch)
指南:
选择控件。
@State private var selectedSize = "Medium"
let sizes = ["Small", "Medium", "Large"]
// 菜单样式
Picker("Size", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.menu)
// 分段样式(适用于 2-5 个选项)
Picker("Size", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.segmented)
选择器样式:
.menu - 下拉菜单(默认).segmented - 分段控件(2-5 个选项).wheel - 可滚动滚轮.inline - 内联列表(在表单中)struct CardView: View {
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Title")
.font(.headline)
Text("Description goes here with some details about the content.")
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
Spacer()
Button("Action") {
// Action
}
.buttonStyle(.borderedProminent)
}
.padding()
.frame(width: 300, height: 200)
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(color: .black.opacity(0.1), radius: 8, x: 0, y: 4)
}
}
苹果的系统字体,专为最佳可读性设计。
// 动态类型文本样式
Text("Large Title").font(.largeTitle) // 34pt
Text("Title").font(.title) // 28pt
Text("Title 2").font(.title2) // 22pt
Text("Title 3").font(.title3) // 20pt
Text("Headline").font(.headline) // 17pt semibold
Text("Body").font(.body) // 17pt regular
Text("Callout").font(.callout) // 16pt
Text("Subheadline").font(.subheadline) // 15pt
Text("Footnote").font(.footnote) // 13pt
Text("Caption").font(.caption) // 12pt
Text("Caption 2").font(.caption2) // 11pt
// 随动态类型缩放的自定义字体
Text("Custom Text")
.font(.custom("YourFont-Regular", size: 17, relativeTo: .body))
Text("Light").fontWeight(.light)
Text("Regular").fontWeight(.regular)
Text("Medium").fontWeight(.medium)
Text("Semibold").fontWeight(.semibold)
Text("Bold").fontWeight(.bold)
Text("Heavy").fontWeight(.heavy)
应做:
不应做:
自动适应浅色/深色模式的色彩。
// UI 元素色彩
Color(.label) // 主要文本
Color(.secondaryLabel) // 次要文本
Color(.tertiaryLabel) // 三级文本
Color(.quaternaryLabel) // 水印文本
Color(.systemBackground) // 主要背景
Color(.secondarySystemBackground) // 次要背景
Color(.tertiarySystemBackground) // 三级背景
Color(.systemFill) // 填充色彩
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
Color(.separator) // 分隔线
Color(.opaqueSeparator) // 不透明分隔线
// 标准系统色彩(适应深色模式)
Color(.systemRed)
Color(.systemOrange)
Color(.systemYellow)
Color(.systemGreen)
Color(.systemMint)
Color(.systemTeal)
Color(.systemCyan)
Color(.systemBlue)
Color(.systemIndigo)
Color(.systemPurple)
Color(.systemPink)
Color(.systemBrown)
Color(.systemGray)
// 定义自适应色彩
extension Color {
static let customBackground = Color("CustomBackground")
}
// 在 Assets.xcassets 中,创建包含以下内容的色彩集:
// - 任何外观: #FFFFFF
// - 深色外观: #000000
WCAG AA 合规性:
自定义色彩:
所有间距应为 8 的倍数。
// 间距值
.padding(8) // 8pt
.padding(16) // 16pt(标准)
.padding(24) // 24pt
.padding(32) // 32pt
.padding(40) // 40pt
.padding(48) // 48pt
// 特定边距的内边距
.padding(.horizontal, 16)
.padding(.vertical, 24)
.padding(.top, 16)
.padding(.bottom, 16)
尊重设备安全区域。
// 安全区域内的内容(默认)
VStack {
Text("Content")
}
// 扩展到安全区域之外
VStack {
Color.blue
}
.ignoresSafeArea()
// 仅扩展顶部
VStack {
Color.blue
}
.ignoresSafeArea(edges: .top)
最小交互尺寸:44x44 点。
Button("Tap") {
// Action
}
.frame(minWidth: 44, minHeight: 44)
// 组件间距
VStack(spacing: 8) { // 紧凑间距
Text("Line 1")
Text("Line 2")
}
VStack(spacing: 16) { // 标准间距
Text("Section 1")
Text("Section 2")
}
VStack(spacing: 24) { // 宽松间距
SectionView()
SectionView()
}
为盲人和低视力用户提供的屏幕阅读器。
// 无障碍标签
Image(systemName: "heart.fill")
.accessibilityLabel("Favorite")
// 无障碍值
Slider(value: $volume)
.accessibilityLabel("Volume")
.accessibilityValue("\(Int(volume * 100))%")
// 无障碍提示
Button("Share") {
share()
}
.accessibilityHint("Shares this item with others")
// 组合元素
HStack {
Image(systemName: "person")
Text("John Doe")
}
.accessibilityElement(children: .combine)
// 对 VoiceOver 隐藏
Image("decorative")
.accessibilityHidden(true)
支持用户偏好的文本大小。
// 系统字体自动支持
Text("This text scales")
.font(.body)
// 限制缩放(如有必要)
Text("This text has limits")
.font(.body)
.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
// 支持动态类型的自定义字体
Text("Custom font")
.font(.custom("YourFont", size: 17, relativeTo: .body))
为色盲用户设计。
// 不要仅依赖颜色
HStack {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
Text("Success")
}
// 不仅仅是颜色
Circle()
.fill(.green)
// ❌ 仅颜色
// 结合形状/图标更好
HStack {
Image(systemName: "checkmark.circle.fill")
Circle().fill(.green)
}
// ✅ 颜色 + 形状
尊重用户的动效偏好。
@Environment(\.accessibilityReduceMotion) var reduceMotion
var animation: Animation {
reduceMotion ? .none : .spring()
}
Button("Animate") {
withAnimation(animation) {
// Animate
}
}
支持高对比度模式。
@Environment(\.colorSchemeContrast) var contrast
var textColor: Color {
contrast == .increased ? .primary : .secondary
}
Text("Content")
.foregroundColor(textColor)
支持浅色和深色外观。
// 使用语义化色彩(自动)
Color(.label) // 自动适应
Color(.systemBackground) // 自动适应
// 预览两种模式
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.preferredColorScheme(.light)
ContentView()
.preferredColorScheme(.dark)
}
}
应做:
不应做:
苹果的图标系统(3000+ 个符号)。
// 基本符号
Image(systemName: "heart")
// 彩色符号
Image(systemName: "heart.fill")
.foregroundColor(.red)
// 调整大小的符号
Image(systemName: "heart")
.imageScale(.large)
// 基于字体的大小调整
Image(systemName: "heart")
.font(.title)
// 多色符号
Image(systemName: "person.crop.circle.fill.badge.checkmark")
.symbolRenderingMode(.multicolor)
// 层级渲染
Image(systemName: "heart.fill")
.symbolRenderingMode(.hierarchical)
.foregroundColor(.red)
iOS:
- 1024x1024 (App Store)
- 180x180 (iPhone @3x)
- 120x120 (iPhone @2x)
- 167x167 (iPad Pro)
- 152x152 (iPad @2x)
watchOS:
- 1024x1024 (App Store)
- 196x196 (49mm)
- 216x216 (45mm)
应做:
不应做:
// 弹簧动画(自然、有弹性)
withAnimation(.spring()) {
offset = 100
}
// 线性动画
withAnimation(.linear(duration: 0.3)) {
opacity = 0
}
// 缓入/缓出
withAnimation(.easeInOut(duration: 0.3)) {
scale = 1.2
}
@State private var offset = CGSize.zero
var body: some View {
Circle()
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in
offset = value.translation
}
.onEnded { _ in
withAnimation(.spring()) {
offset = .zero
}
}
)
}
struct LoadingView: View {
var body: some View {
VStack {
ProgressView()
.scaleEffect(1.5)
Text("Loading...")
.font(.caption)
.foregroundColor(.secondary)
.padding(.top)
}
}
}
struct ErrorView: View {
let message: String
let retry: () -> Void
var body: some View {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 48))
.foregroundColor(.orange)
Text("Something went wrong")
.font(.headline)
Text(message)
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Button("Try Again") {
retry()
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
struct EmptyStateView: View {
var body: some View {
VStack(spacing: 16) {
Image(systemName: "tray")
.font(.system(size: 64))
.foregroundColor(.secondary)
Text("No Items")
.font(.title2)
Text("Your items will appear here")
.font(.subheadline)
.foregroundColor(.secondary)
Button("Add Item") {
// Action
}
.buttonStyle(.borderedProminent)
}
}
}
“设计不仅仅是外观和感觉。设计关乎如何运作。” - 史蒂夫·乔布斯
每周安装量
496
代码仓库
GitHub 星标数
102
首次出现
2026年1月20日
安全审计
安装于
opencode453
gemini-cli439
codex437
github-copilot404
cursor381
claude-code368
Design beautiful, native iOS apps following Apple's Human Interface Guidelines (HIG). Create accessible, intuitive interfaces with native components, proper typography, semantic colors, and Apple's design principles.
Helps you design and build iOS apps that feel native and follow Apple's guidelines:
Make content clear and focused.
Text is legible at every size, icons are precise and lucid, adornments are subtle and appropriate, and a focus on functionality drives the design.
// ✅ Clear, focused content
Text("Welcome back, Sarah")
.font(.title)
.foregroundColor(.primary)
// ❌ Unclear, cluttered
Text("Welcome back, Sarah!!!")
.font(.title)
.foregroundColor(.red)
.background(.yellow)
.overlay(Image(systemName: "star.fill"))
UI helps people understand and interact with content, but never competes with it.
The interface defers to content, using a light visual treatment that keeps focus on the content and gives the content room to breathe.
// ✅ Content-focused
VStack(alignment: .leading, spacing: 8) {
Text("Article Title")
.font(.headline)
Text("Article content goes here...")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
// ❌ Distracting UI
VStack(spacing: 8) {
Text("Article Title")
.font(.headline)
.foregroundColor(.white)
.background(.blue)
.border(.red, width: 3)
}
Visual layers and realistic motion convey hierarchy and help people understand relationships.
Distinct visual layers and realistic motion impart vitality and facilitate understanding. Touch and discoverability heighten delight and enable access to functionality without losing context.
// ✅ Clear depth hierarchy
ZStack {
Color(.systemBackground)
VStack {
// Card with elevation
CardView()
.shadow(radius: 8)
}
}
// Using blur for depth
Text("Content")
.background(.ultraThinMaterial)
Top bar for navigation and actions.
NavigationStack {
List {
Text("Item 1")
Text("Item 2")
}
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Add") {
// Action
}
}
}
}
Guidelines:
Bottom navigation for top-level destinations.
TabView {
HomeView()
.tabItem {
Label("Home", systemImage: "house")
}
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
ProfileView()
.tabItem {
Label("Profile", systemImage: "person")
}
}
Guidelines:
Scrollable list of items.
List {
Section("Today") {
ForEach(items) { item in
NavigationLink {
DetailView(item: item)
} label: {
HStack {
Image(systemName: item.icon)
.foregroundColor(.accentColor)
Text(item.title)
}
}
}
}
}
.listStyle(.insetGrouped)
List Styles:
.plain - Edge-to-edge rows.insetGrouped - Rounded, inset sections (iOS default).sidebar - For navigation sidebarsPresent content modally.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Show Details") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
DetailView()
.presentationDetents([.medium, .large])
}
}
}
Sheet Detents:
.medium - Half screen.large - Full screenPrimary action control.
// Filled button (primary action)
Button("Continue") {
// Action
}
.buttonStyle(.borderedProminent)
// Bordered button (secondary action)
Button("Cancel") {
// Action
}
.buttonStyle(.bordered)
// Plain button (tertiary action)
Button("Learn More") {
// Action
}
.buttonStyle(.plain)
Button Hierarchy:
Guidelines:
Text input control.
@State private var username = ""
@State private var password = ""
VStack(alignment: .leading, spacing: 16) {
// Standard text field
TextField("Username", text: $username)
.textFieldStyle(.roundedBorder)
.textContentType(.username)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
// Secure field
SecureField("Password", text: $password)
.textFieldStyle(.roundedBorder)
.textContentType(.password)
}
Text Content Types:
.username - Username field.password - Password field.emailAddress - Email field.telephoneNumber - Phone number.creditCardNumber - Credit cardBoolean control (switch).
@State private var isEnabled = false
Toggle("Enable notifications", isOn: $isEnabled)
.toggleStyle(.switch)
Guidelines:
Selection control.
@State private var selectedSize = "Medium"
let sizes = ["Small", "Medium", "Large"]
// Menu style
Picker("Size", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.menu)
// Segmented style (for 2-5 options)
Picker("Size", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.segmented)
Picker Styles:
.menu - Dropdown menu (default).segmented - Segmented control (2-5 options).wheel - Scrollable wheel.inline - Inline list (in forms)struct CardView: View {
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Title")
.font(.headline)
Text("Description goes here with some details about the content.")
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
Spacer()
Button("Action") {
// Action
}
.buttonStyle(.borderedProminent)
}
.padding()
.frame(width: 300, height: 200)
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(color: .black.opacity(0.1), radius: 8, x: 0, y: 4)
}
}
Apple's system font designed for optimal legibility.
// Dynamic Type text styles
Text("Large Title").font(.largeTitle) // 34pt
Text("Title").font(.title) // 28pt
Text("Title 2").font(.title2) // 22pt
Text("Title 3").font(.title3) // 20pt
Text("Headline").font(.headline) // 17pt semibold
Text("Body").font(.body) // 17pt regular
Text("Callout").font(.callout) // 16pt
Text("Subheadline").font(.subheadline) // 15pt
Text("Footnote").font(.footnote) // 13pt
Text("Caption").font(.caption) // 12pt
Text("Caption 2").font(.caption2) // 11pt
// Custom font that scales with Dynamic Type
Text("Custom Text")
.font(.custom("YourFont-Regular", size: 17, relativeTo: .body))
Text("Light").fontWeight(.light)
Text("Regular").fontWeight(.regular)
Text("Medium").fontWeight(.medium)
Text("Semibold").fontWeight(.semibold)
Text("Bold").fontWeight(.bold)
Text("Heavy").fontWeight(.heavy)
Do:
Don't:
Colors that automatically adapt to light/dark mode.
// UI Element Colors
Color(.label) // Primary text
Color(.secondaryLabel) // Secondary text
Color(.tertiaryLabel) // Tertiary text
Color(.quaternaryLabel) // Watermark text
Color(.systemBackground) // Primary background
Color(.secondarySystemBackground) // Secondary background
Color(.tertiarySystemBackground) // Tertiary background
Color(.systemFill) // Fill colors
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
Color(.separator) // Separator lines
Color(.opaqueSeparator) // Non-transparent separator
// Standard system colors (adapt to dark mode)
Color(.systemRed)
Color(.systemOrange)
Color(.systemYellow)
Color(.systemGreen)
Color(.systemMint)
Color(.systemTeal)
Color(.systemCyan)
Color(.systemBlue)
Color(.systemIndigo)
Color(.systemPurple)
Color(.systemPink)
Color(.systemBrown)
Color(.systemGray)
// Define adaptive color
extension Color {
static let customBackground = Color("CustomBackground")
}
// In Assets.xcassets, create color set with:
// - Any Appearance: #FFFFFF
// - Dark Appearance: #000000
WCAG AA Compliance:
Custom colors:
All spacing should be multiples of 8.
// Spacing values
.padding(8) // 8pt
.padding(16) // 16pt (standard)
.padding(24) // 24pt
.padding(32) // 32pt
.padding(40) // 40pt
.padding(48) // 48pt
// Edge-specific padding
.padding(.horizontal, 16)
.padding(.vertical, 24)
.padding(.top, 16)
.padding(.bottom, 16)
Respect device safe areas.
// Content within safe area (default)
VStack {
Text("Content")
}
// Extend beyond safe area
VStack {
Color.blue
}
.ignoresSafeArea()
// Extend top only
VStack {
Color.blue
}
.ignoresSafeArea(edges: .top)
Minimum interactive size: 44x44 points.
Button("Tap") {
// Action
}
.frame(minWidth: 44, minHeight: 44)
// Component spacing
VStack(spacing: 8) { // Tight spacing
Text("Line 1")
Text("Line 2")
}
VStack(spacing: 16) { // Standard spacing
Text("Section 1")
Text("Section 2")
}
VStack(spacing: 24) { // Loose spacing
SectionView()
SectionView()
}
Screen reader for blind and low-vision users.
// Accessible label
Image(systemName: "heart.fill")
.accessibilityLabel("Favorite")
// Accessible value
Slider(value: $volume)
.accessibilityLabel("Volume")
.accessibilityValue("\(Int(volume * 100))%")
// Accessible hint
Button("Share") {
share()
}
.accessibilityHint("Shares this item with others")
// Group elements
HStack {
Image(systemName: "person")
Text("John Doe")
}
.accessibilityElement(children: .combine)
// Hidden from VoiceOver
Image("decorative")
.accessibilityHidden(true)
Support user's preferred text size.
// Automatically supported with system fonts
Text("This text scales")
.font(.body)
// Limit scaling (if necessary)
Text("This text has limits")
.font(.body)
.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
// Custom font with Dynamic Type
Text("Custom font")
.font(.custom("YourFont", size: 17, relativeTo: .body))
Design for color-blind users.
// Don't rely on color alone
HStack {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
Text("Success")
}
// Not just color
Circle()
.fill(.green)
// ❌ Color only
// Better with shape/icon
HStack {
Image(systemName: "checkmark.circle.fill")
Circle().fill(.green)
}
// ✅ Color + shape
Respect user's motion preferences.
@Environment(\.accessibilityReduceMotion) var reduceMotion
var animation: Animation {
reduceMotion ? .none : .spring()
}
Button("Animate") {
withAnimation(animation) {
// Animate
}
}
Support high contrast mode.
@Environment(\.colorSchemeContrast) var contrast
var textColor: Color {
contrast == .increased ? .primary : .secondary
}
Text("Content")
.foregroundColor(textColor)
Support both light and dark appearances.
// Use semantic colors (automatic)
Color(.label) // Adapts automatically
Color(.systemBackground) // Adapts automatically
// Preview both modes
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.preferredColorScheme(.light)
ContentView()
.preferredColorScheme(.dark)
}
}
Do:
Don't:
Apple's icon system (3000+ symbols).
// Basic symbol
Image(systemName: "heart")
// Colored symbol
Image(systemName: "heart.fill")
.foregroundColor(.red)
// Sized symbol
Image(systemName: "heart")
.imageScale(.large)
// Font-based sizing
Image(systemName: "heart")
.font(.title)
// Multicolor symbols
Image(systemName: "person.crop.circle.fill.badge.checkmark")
.symbolRenderingMode(.multicolor)
// Hierarchical rendering
Image(systemName: "heart.fill")
.symbolRenderingMode(.hierarchical)
.foregroundColor(.red)
iOS:
- 1024x1024 (App Store)
- 180x180 (iPhone @3x)
- 120x120 (iPhone @2x)
- 167x167 (iPad Pro)
- 152x152 (iPad @2x)
watchOS:
- 1024x1024 (App Store)
- 196x196 (49mm)
- 216x216 (45mm)
Do:
Don't:
// Spring animation (natural, bouncy)
withAnimation(.spring()) {
offset = 100
}
// Linear animation
withAnimation(.linear(duration: 0.3)) {
opacity = 0
}
// Ease in/out
withAnimation(.easeInOut(duration: 0.3)) {
scale = 1.2
}
@State private var offset = CGSize.zero
var body: some View {
Circle()
.offset(offset)
.gesture(
DragGesture()
.onChanged { value in
offset = value.translation
}
.onEnded { _ in
withAnimation(.spring()) {
offset = .zero
}
}
)
}
struct LoadingView: View {
var body: some View {
VStack {
ProgressView()
.scaleEffect(1.5)
Text("Loading...")
.font(.caption)
.foregroundColor(.secondary)
.padding(.top)
}
}
}
struct ErrorView: View {
let message: String
let retry: () -> Void
var body: some View {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 48))
.foregroundColor(.orange)
Text("Something went wrong")
.font(.headline)
Text(message)
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Button("Try Again") {
retry()
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
struct EmptyStateView: View {
var body: some View {
VStack(spacing: 16) {
Image(systemName: "tray")
.font(.system(size: 64))
.foregroundColor(.secondary)
Text("No Items")
.font(.title2)
Text("Your items will appear here")
.font(.subheadline)
.foregroundColor(.secondary)
Button("Add Item") {
// Action
}
.buttonStyle(.borderedProminent)
}
}
}
"Design is not just what it looks like and feels like. Design is how it works." - Steve Jobs
Weekly Installs
496
Repository
GitHub Stars
102
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode453
gemini-cli439
codex437
github-copilot404
cursor381
claude-code368
前端设计技能指南:避免AI垃圾美学,打造独特生产级界面
36,100 周安装