mcpField
S
swift-uikit

swift-uikit

github.com/pluginagentmarketplace开发861 次安装43 周前更新
代码仓库

关于 swift-uikit

为构建传统 iOS 界面的开发者提供 UIKit 指引,涵盖视图控制器、自动布局、表格与集合视图,以及常见问题排查。内容还包括无障碍和动态字体检查。

主要功能

  1. 01视图控制器模式与导航
  2. 02Auto Layout 约束
  3. 03表格视图与集合视图布局
  4. 04无障碍与动态字体检查
  5. 05常见 UIKit 问题排查指引

适用场景

  1. 01通过代码或 storyboard 构建 UIKit 界面
  2. 02创建列表和网格界面
  3. 03排查约束冲突或单元格未显示
  4. 04检查无障碍与动态字体支持

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-swift --skill swift-uikit

安装后在 Claude Code 中输入/swift-uikit确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
config.yaml
schema.json
ViewController.swift.template
references/
GUIDE.md
PATTERNS.md
scripts/
validate.py

详细介绍

UIKit 技能

用于构建传统 iOS 用户界面的 UIKit 框架综合知识。

前提条件

  • 已安装 Xcode 15+
  • 建议将 iOS 15+ 设为部署目标
  • 了解 MVC/MVVM 模式

参数

parameters:
  layout_approach:
    type: string
    enum: [programmatic, storyboard, xib]
    default: programmatic
  accessibility_enabled:
    type: boolean
    default: true
  dynamic_type_support:
    type: boolean
    default: true

涵盖主题

视图控制器
类型用途使用场景
UIViewController基础控制器自定义屏幕
UINavigationController堆栈导航层级流程
UITabBarController基于标签页的导航主要分区
UISplitViewController主从视图iPad 布局
UIPageViewController页面滑动引导流程
自动布局
约束类型描述
Leading/Trailing水平边缘(支持 RTL)
Top/Bottom垂直边缘
CenterX/CenterY居中对齐
Width/Height尺寸约束
Aspect Ratio比例尺寸
表格视图与集合视图
组件用途
UITableView垂直滚动列表
UICollectionView灵活的网格布局
DiffableDataSource自动差异计算(iOS 13+)
CompositionalLayout复杂布局(iOS 13+)

代码示例

以编程方式创建视图控制器
final class ProfileViewController: UIViewController {
    // MARK: - UI Components

    private lazy var avatarImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.layer.cornerRadius = 50
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.accessibilityLabel = "Profile picture"
        return imageView
    }()

    private lazy var nameLabel: UILabel = {
        let label = UILabel()
        label.font = .preferredFont(forTextStyle: .title1)
        label.adjustsFontForContentSizeCategory = true
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private lazy var bioLabel: UILabel = {
        let label = UILabel()
        label.font = .preferredFont(forTextStyle: .body)
        label.adjustsFontForContentSizeCategory = true
        label.numberOfLines = 0
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupConstraints()
    }

    // MARK: - Setup

    private func setupUI() {
        view.backgroundColor = .systemBackground
        view.addSubview(avatarImageView)
        view.addSubview(nameLabel)
        view.addSubview(bioLabel)
    }

    private func setupConstraints() {
        NSLayoutConstraint.activate([
            avatarImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 32),
            avatarImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            avatarImageView.widthAnchor.constraint(equalToConstant: 100),
            avatarImageView.heightAnchor.constraint(equalToConstant: 100),

            nameLabel.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 16),
            nameLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            nameLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),

            bioLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 8),
            bioLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            bioLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
        ])
    }

    // MARK: - Configuration

    func configure(with user: User) {
        nameLabel.text = user.name
        bioLabel.text = user.bio
        // Load avatar image
    }
}
使用 Diffable Data Source 的现代集合视图
final class ProductGridViewController: UIViewController {
    enum Section { case main }

    private var collectionView: UICollectionView!
    private var dataSource: UICollectionViewDiffableDataSource<Section, Product>!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureCollectionView()
        configureDataSource()
    }

    private func configureCollectionView() {
        let layout = createCompositionalLayout()
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        collectionView.backgroundColor = .systemBackground
        view.addSubview(collectionView)
    }

    private func createCompositionalLayout() -> UICollectionViewLayout {
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(0.5),
            heightDimension: .estimated(200)
        )
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)

        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .estimated(200)
        )
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        return UICollectionViewCompositionalLayout(section: section)
    }

    private func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<ProductCell, Product> { cell, indexPath, product in
            cell.configure(with: product)
        }

        dataSource = UICollectionViewDiffableDataSource<Section, Product>(collectionView: collectionView) {
            collectionView, indexPath, product in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: product)
        }
    }

    func applySnapshot(products: [Product], animatingDifferences: Bool = true) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Product>()
        snapshot.appendSections([.main])
        snapshot.appendItems(products)
        dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
    }
}
具有固有尺寸的自定义 UIView
final class TagView: UIView {
    private let label: UILabel = {
        let label = UILabel()
        label.font = .preferredFont(forTextStyle: .caption1)
        label.adjustsFontForContentSizeCategory = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private let padding = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)

    override var intrinsicContentSize: CGSize {
        let labelSize = label.intrinsicContentSize
        return CGSize(
            width: labelSize.width + padding.left + padding.right,
            height: labelSize.height + padding.top + padding.bottom
        )
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    private func setup() {
        backgroundColor = .systemBlue
        layer.cornerRadius = 8

        addSubview(label)
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: topAnchor, constant: padding.top),
            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.left),
            label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding.right),
            label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding.bottom)
        ])
    }

    func configure(text: String, color: UIColor = .systemBlue) {
        label.text = text
        label.textColor = .white
        backgroundColor = color
        invalidateIntrinsicContentSize()
    }
}

故障排除

常见问题
问题原因解决方案
“无法同时满足约束”约束冲突降低灵活约束的优先级
单元格未显示未注册使用 CellRegistration,或在出列前注册
键盘遮挡文本字段未处理键盘监听键盘通知
内容被压缩缺少抗压缩优先级提高内容抗压缩优先级
视图无法响应触摸视图重叠检查视图层级和 userInteractionEnabled
调试命令
// Print view hierarchy
po view.recursiveDescription()

// Print Auto Layout issues
po view.constraintsAffectingLayout(for: .horizontal)

// Check if on main thread
assert(Thread.isMainThread, "UI updates must be on main thread")

验证规则

validation:
  - rule: accessibility_labels
    severity: warning
    check: All interactive elements must have accessibility labels
  - rule: dynamic_type_support
    severity: warning
    check: Use preferredFont and adjustsFontForContentSizeCategory
  - rule: safe_area_constraints
    severity: info
    check: Content should respect safe area layout guides

使用方法

Skill("swift-uikit")

相关技能

  • swift-ios-basics - iOS 基础知识
  • swift-swiftui - 现代替代方案
  • swift-architecture - 应用架构

评论

支持 Markdown