Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计通过

swift-ios-uiSwift iOS UI 浏览器

Agent Skill

用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。它适合让 Agent 根据产品场景整理页面结构、生成 UI 方案、检查视觉一致性或改进组件层级。使用时需要结合现有品牌、设计系统和用户任务,不应只堆装饰元素;涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出、对齐和响应式表现。

总安装

465

周安装

19

GitHub Stars

公开资料未说明

下载量

149
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:swift-ios-ui(Swift iOS UI 浏览器)
来源仓库:https://github.com/qunwang6/swift-ios-ui
仓库路径:skills/swift-ios-ui
安装命令:
npx skills add https://github.com/qunwang6/swift-ios-ui --skill swift-ios-ui
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/qunwang6/swift-ios-ui --skill swift-ios-ui

简介

swift-ios-ui 用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。

  • 适合让 Agent 根据产品场景整理页面结构、生成 UI 方案或检查视觉一致性。
  • 使用时需结合现有品牌、设计系统和用户任务,避免堆砌装饰元素。
  • 涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出和对齐表现。
  • 安装前需确认权限范围、维护状态及是否触发联网或文件读写操作。

SKILL.md

Swift iOS UI Skill

Generate production-quality iOS UIKit code from UI designs, screenshots, or descriptions.

Tech Stack (Always Use These)

PurposeLibrary
LayoutSnapKit — Auto Layout DSL
Popups / ToastsSwiftEntryKit
Image LoadingKingfisher or SDWebImage
JSON ParsingSwiftyJSON

Step-by-Step Workflow

0. Understand the Input

The user may provide one of the following — adapt accordingly:

Input typeHow to handle
Screenshot / imageCarefully read all visible text, colors, layout, spacing, component types
Figma / Sketch descriptionExtract component hierarchy, spacing tokens, color styles
Text descriptionAsk clarifying questions if key details (colors, layout direction, data shape) are missing
No input yetAsk the user: "Please share a UI screenshot, design spec, or describe the screen you want to build."
⚠️ Do NOT start generating code until you have enough UI information. If the user provides a screenshot, analyze it fully before writing a single line.

1. Analyze the UI

Before writing any code, examine the design and identify:

  • Screen type: full screen / modal / bottom sheet / popup
  • Layout structure: navigation bar, scroll view, table/collection view, static views
  • Components: buttons, labels, images, text fields, cards, cells
  • Colors: extract hex values from the design (or best-match hex if approximate)
  • Spacing: margins, padding, gaps between elements
  • Interactive states: normal / highlighted / disabled / loading / empty / error

2. Plan the Architecture

Choose the right UIKit pattern:

  • UIViewController + UIScrollView → scrollable content screens
  • UIViewController + UITableView → list screens
  • UIViewController + UICollectionView → grid / complex layouts
  • UIView subclass → reusable components / cells
  • SwiftEntryKit → popups, toasts, bottom sheets, alerts

3. Generate the Code

Follow all conventions in the Code Conventions section below.

4. Output Structure

For each screen, produce:

  1. Main ViewController or View file
  2. Any custom UITableViewCell / UICollectionViewCell subclasses
  3. Any reusable subviews extracted as separate UIView subclasses
  4. A Model struct/class if JSON data is involved

Code Conventions

File Structure

// MARK: - Properties
// MARK: - Lifecycle
// MARK: - Setup
// MARK: - Layout (SnapKit)
// MARK: - Actions
// MARK: - Data / Network
// MARK: - Helpers

SnapKit Layout Rules

  • Always call setupUI() and setupConstraints() from viewDidLoad (or init for UIView)
  • Add subviews in setupUI(), define constraints in setupConstraints()
  • Never use frame or autoresizingMask — SnapKit only
  • Write spacing values directly as literals in SnapKit constraints — do NOT define enum Layout or extract values to named constants.
// ✅ Correct SnapKit usage
private func setupConstraints() {
    titleLabel.snp.makeConstraints { make in
        make.top.equalTo(headerView.snp.bottom).offset(16)
        make.leading.trailing.equalToSuperview().inset(16)
    }

    confirmButton.snp.makeConstraints { make in
        make.bottom.equalTo(view.safeAreaLayoutGuide).inset(16)
        make.leading.trailing.equalToSuperview().inset(16)
        make.height.equalTo(50)
    }
}

Typography — PingFangSC (Always Use This)

⚠️ Never use .systemFont or raw UIFont(name:) strings — always use .pingFangSC() via the extension below.UIFont+PingFangSC.swift already exists in the project. Do NOT output this extension definition in generated code — just call it directly.
// UIFont+PingFangSC.swift — include this extension in every project
extension UIFont {
    enum PingFangSC: String {
        case ultralight = "PingFangSC-Ultralight"
        case thin       = "PingFangSC-Thin"
        case light      = "PingFangSC-Light"
        case regular    = "PingFangSC-Regular"
        case medium     = "PingFangSC-Medium"
        case semibold   = "PingFangSC-Semibold"
    }

    static func pingFangSC(_ style: PingFangSC, size: CGFloat) -> UIFont {
        return UIFont(name: style.rawValue, size: size) ?? .systemFont(ofSize: size)
    }
}

Usage reference:

WeightCallTypical use
Ultralight.pingFangSC(.ultralight, size: n)Decorative, large display numbers
Thin.pingFangSC(.thin, size: n)Subtle secondary info
Light.pingFangSC(.light, size: n)Body text, descriptions
Regular.pingFangSC(.regular, size: n)Default body / labels
Medium.pingFangSC(.medium, size: n)Emphasized labels, button text
Semibold.pingFangSC(.semibold, size: n)Titles, nav bar, headers
// ✅ Correct — always call the extension method
titleLabel.font    = .pingFangSC(.semibold, size: 18)
bodyLabel.font     = .pingFangSC(.regular, size: 14)
priceLabel.font    = .pingFangSC(.medium, size: 16)
subtitleLabel.font = .pingFangSC(.light, size: 13)

// ❌ Never do this
titleLabel.font = .systemFont(ofSize: 18, weight: .semibold)
titleLabel.font = UIFont(name: "PingFangSC-Semibold", size: 18)  // raw string usage forbidden

Colors — UIColor.colorWithHexString (Always Use This)

⚠️ Never use UIColor(hexString:), UIColor(hex:), Hue, or SwiftHEXColors — always use UIColor.colorWithHexString(hex:) via the extension below.UIColor+Hex.swift already exists in the project. Do NOT output this extension definition in generated code — just call it directly.
// UIColor+Hex.swift — include this extension in every project
extension UIColor {
    static func colorWithHexString(hex: String) -> UIColor {
        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
        hexSanitized = hexSanitized.hasPrefix("#") ? String(hexSanitized.dropFirst()) : hexSanitized

        var rgb: UInt64 = 0
        Scanner(string: hexSanitized).scanHexInt64(&rgb)

        let r = CGFloat((rgb & 0xFF0000) >> 16) / 255.0
        let g = CGFloat((rgb & 0x00FF00) >> 8)  / 255.0
        let b = CGFloat(rgb & 0x0000FF)          / 255.0

        return UIColor(red: r, green: g, blue: b, alpha: 1.0)
    }
}

Usage:

❌ Do NOT define `enum AppColor` or any named color constants — write hex values inline directly.
// ✅ Correct
let primary = UIColor.colorWithHexString(hex: "#007AFF")
let dimmed  = UIColor.colorWithHexString(hex: "#212226").withAlphaComponent(0.5)

// ❌ Never do this
let c1 = UIColor(hexString: "#FF6B35")   // SwiftHEXColors — forbidden
let c2 = UIColor(hex: "#2C3E50")         // SwiftHEXColors — forbidden
let c3 = primary.lighten(byAmount: 0.2)  // Hue — forbidden

Image Loading with Kingfisher

// Basic
imageView.kf.setImage(with: URL(string: urlString))

// With placeholder + options
imageView.kf.setImage(
    with: URL(string: urlString),
    placeholder: UIImage(named: "placeholder"),
    options: [
        .transition(.fade(0.25)),
        .cacheOriginalImage
    ]
)

// Cancel on reuse (in UITableViewCell)
override func prepareForReuse() {
    super.prepareForReuse()
    imageView.kf.cancelDownloadTask()
    imageView.image = nil
}

JSON Parsing with SwiftyJSON

import SwiftyJSON

struct UserModel {
    let id: Int
    let name: String
    let avatar: String
    let score: Double

    init(json: JSON) {
        self.id     = json["id"].intValue
        self.name   = json["name"].stringValue
        self.avatar = json["avatar"].stringValue
        self.score  = json["score"].doubleValue
    }

    static func list(from json: JSON) -> [UserModel] {
        return json.arrayValue.map { UserModel(json: $0) }
    }
}

Localization — LocalizableManager (Always Use This)

⚠️ Never use hardcoded strings for UI text — always use LocalizableManager.localValue("key").
// ✅ Correct
titleLabel.text = LocalizableManager.localValue("register_email")

// ❌ Never do this
titleLabel.text = "Email"
titleLabel.text = "邮箱"

When generating any UI text, you must also output the corresponding localization keys and translations for all 3 languages.

Output format — one table per file:

KeyEnglishSimplified ChineseTraditional Chinese
register_email"Email""邮箱""郵箱"

en.lproj/Localizable.strings

"register_email" = "Email";

zh-Hans.lproj/Localizable.strings

"register_email" = "邮箱";

zh-Hant.lproj/Localizable.strings

"register_email" = "郵箱";

Key naming convention:

PatternExample
{screen}_{element}register_email, login_password, profile_save_button
{screen}_titleregister_title, cart_title
{screen}_hint_{field}register_hint_email, login_hint_password
common_{action}common_confirm, common_cancel, common_save
✅ Keys must be lowercase snake_case. Never reuse keys across unrelated screens.

SwiftEntryKit — Popups & Toasts

Toast / Snackbar

func showToast(message: String, isSuccess: Bool = true) {
    var attributes = EKAttributes.topToast
    attributes.entryBackground = .color(color: EKColor(isSuccess ? AppColor.primary : .systemRed))
    attributes.displayDuration = 2.5
    attributes.shadow = .active(with: .init(color: .black, opacity: 0.2, radius: 6))

    let style = EKProperty.LabelStyle(
        font: .pingFangSC(.medium, size: 14),
        color: EKColor(.white)
    )
    let labelContent = EKProperty.LabelContent(text: message, style: style)
    let contentView = EKNoteMessageView(with: labelContent)
    SwiftEntryKit.display(entry: contentView, using: attributes)
}

Center Alert Popup

func showAlertPopup(title: String, message: String, confirmAction: @escaping () -> Void) {
    var attributes = EKAttributes.centerFloat
    attributes.entryBackground = .color(color: EKColor(.white))
    attributes.roundCorners = .all(radius: 16)
    attributes.shadow = .active(with: .init(color: .black, opacity: 0.15, radius: 10))
    attributes.screenInteraction = .absorbTouches
    attributes.entryInteraction = .absorbTouches
    attributes.displayDuration = .infinity

    // Build your custom UIView popup, then:
    let popupView = CustomAlertView(title: title, message: message)
    popupView.onConfirm = {
        SwiftEntryKit.dismiss()
        confirmAction()
    }
    SwiftEntryKit.display(entry: popupView, using: attributes)
}

Bottom Sheet ⚠️ Always use this exact configuration

/// Standard bottom sheet — MUST use this attribute setup exactly.
/// popupView is a UIView subclass that self-sizes via its own constraints (height: .intrinsic).
func showBottomSheet(popupView: UIView) {
    var attributes = EKAttributes()
    attributes.position = .bottom
    attributes.displayDuration = .infinity
    attributes.screenBackground = .color(
        color: .init(
            light: UIColor(white: 0, alpha: 0.4),
            dark:  UIColor(white: 0, alpha: 0.4)
        )
    )
    attributes.entryBackground = .clear           // popup view draws its own background
    attributes.screenInteraction = .dismiss        // tap outside to dismiss
    attributes.entryInteraction = .forward         // touches pass through to content
    attributes.scroll = .disabled
    attributes.positionConstraints.size = .init(width: .fill, height: .intrinsic)
    attributes.positionConstraints.safeArea = .overridden  // extend under home indicator
    attributes.positionConstraints.verticalOffset = 0

    SwiftEntryKit.display(entry: popupView, using: attributes)
}

// Dismiss from inside the popup:
// SwiftEntryKit.dismiss()
Rules for the popup UIView: - Draw its own background (white + top rounded corners) — NOT via entryBackground - Use SnapKit so the view's intrinsic height is driven by its own content constraints - Add a bottom padding area to account for home indicator
final class SampleBottomSheetView: UIView {

    // MARK: - UI
    private let containerView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        v.layer.cornerRadius = 20
        v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        v.clipsToBounds = true
        return v
    }()

    // MARK: - Init
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
        setupConstraints()
    }
    required init?(coder: NSCoder) { fatalError() }

    // MARK: - Setup
    private func setupUI() {
        backgroundColor = .clear
        addSubview(containerView)
        // add content subviews to containerView...
    }

    private func setupConstraints() {
        containerView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            // ⚠️ Do NOT pin bottom to superview — let content drive height
        }
        // ...content constraints inside containerView...

        // Safe-area bottom padding (home indicator)
        let bottomPadding: CGFloat = 34
        containerView.snp.makeConstraints { make in
            make.bottom.equalToSuperview().inset(0)
        }
        // Add a spacer view at the bottom of containerView with height 34
    }
}

UITableView / UICollectionView Best Practices

// Cell registration
tableView.register(ProductCell.self, forCellReuseIdentifier: ProductCell.reuseId)

// Cell class template
final class ProductCell: UITableViewCell {
    static let reuseId = "ProductCell"

    // MARK: - UI
    private let containerView = UIView()
    private let thumbImageView = UIImageView()
    private let titleLabel = UILabel()
    private let priceLabel = UILabel()

    // MARK: - Init
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
        setupConstraints()
    }
    required init?(coder: NSCoder) { fatalError() }

    // MARK: - Setup
    private func setupUI() {
        selectionStyle = .none
        contentView.addSubview(containerView)
        containerView.addSubview(thumbImageView)
        containerView.addSubview(titleLabel)
        containerView.addSubview(priceLabel)

        titleLabel.font  = .pingFangSC(.medium, size: 15)
        titleLabel.textColor = UIColor.colorWithHexString(hex: "#2D2F35")
        priceLabel.font  = .pingFangSC(.semibold, size: 16)
        priceLabel.textColor = UIColor.colorWithHexString(hex: "#149D93")
    }

    private func setupConstraints() {
        containerView.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16))
        }
        thumbImageView.snp.makeConstraints { make in
            make.leading.top.bottom.equalToSuperview()
            make.width.height.equalTo(80)
        }
        titleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.leading.equalTo(thumbImageView.snp.trailing).offset(12)
            make.trailing.equalToSuperview().inset(12)
        }
        priceLabel.snp.makeConstraints { make in
            make.bottom.equalToSuperview().inset(12)
            make.leading.equalTo(thumbImageView.snp.trailing).offset(12)
        }
    }

    // MARK: - Configure
    func configure(with model: ProductModel) {
        titleLabel.text = model.name
        priceLabel.text = "¥\(model.price)"
        thumbImageView.kf.setImage(with: URL(string: model.imageUrl), placeholder: UIImage(named: "placeholder"))
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        thumbImageView.kf.cancelDownloadTask()
        thumbImageView.image = nil
    }
}

Navigation Bar Customization

private func setupNavigationBar() {
    title = "Page Title"
    navigationController?.navigationBar.tintColor = AppColor.primary
    navigationController?.navigationBar.titleTextAttributes = [
        .foregroundColor: AppColor.text,
        .font: UIFont.pingFangSC(.semibold, size: 17)
    ]
    // Right bar button
    let rightBtn = UIBarButtonItem(image: UIImage(systemName: "bell"),
                                   style: .plain,
                                   target: self,
                                   action: #selector(rightButtonTapped))
    navigationItem.rightBarButtonItem = rightBtn
}

Empty State & Loading State

// Loading
func showLoading() {
    let indicator = UIActivityIndicatorView(style: .medium)
    indicator.tag = 999
    indicator.startAnimating()
    view.addSubview(indicator)
    indicator.snp.makeConstraints { $0.center.equalToSuperview() }
}

func hideLoading() {
    view.viewWithTag(999)?.removeFromSuperview()
}

// Empty state
func showEmptyState(message: String = "暂无数据") {
    let label = UILabel()
    label.text = message
    label.textColor = AppColor.subtext
    label.font = .pingFangSC(.regular, size: 15)
    label.tag = 998
    view.addSubview(label)
    label.snp.makeConstraints { $0.center.equalToSuperview() }
}

Output Checklist

Before finishing, verify:

  • No frame / AutoresizingMask usage — SnapKit only
  • All fonts use .pingFangSC() extension — never .systemFont or raw UIFont(name:) strings
  • Safe area insets handled (safeAreaLayoutGuide)
  • All colors use UIColor.colorWithHexString(hex:) inline — no AppColor enum, never Hue or SwiftHEXColors
  • Images use kf.setImage with placeholder
  • prepareForReuse cancels Kingfisher tasks in cells
  • JSON models use SwiftyJSON with init(json: JSON)
  • Popups use SwiftEntryKit (no UIAlertController unless truly native alert)
  • All UI created programmatically (no Storyboard/XIB unless asked)
  • // MARK: sections used for code organization
  • Spacing values written as inline literals — no enum Layout
  • Bottom sheets use the exact EKAttributes config from the Bottom Sheet section (never EKAttributes.bottomFloat)
  • Bottom sheet popup view sets entryBackground =.clear and draws its own background
  • Bottom sheet config includes safeArea =.overridden and verticalOffset = 0
  • Do NOT output extension UIFont or extension UIColor definitions — these extensions already exist in the project
  • All UI strings use LocalizableManager.localValue("key") — no hardcoded text
  • Localization keys follow {screen}_{element} naming convention
  • All 3 language translations are output alongside the code: en, zh-Hans, zh-Hant

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.97%
按下载量换算55

Claude

27.71%
按下载量换算41

Cursor

18.88%
按下载量换算28

Gemini CLI

9.77%
按下载量换算15

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills