swift-uikit

Master UIKit for iOS app development - views, view controllers, Auto Layout, table/collection views

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "swift-uikit" with this command: npx skills add pluginagentmarketplace/custom-plugin-swift/pluginagentmarketplace-custom-plugin-swift-swift-uikit

UIKit Skill

Comprehensive UIKit framework knowledge for building traditional iOS user interfaces.

Prerequisites

  • Xcode 15+ installed
  • iOS 15+ deployment target recommended
  • Understanding of MVC/MVVM patterns

Parameters

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

Topics Covered

View Controllers

TypePurposeUse Case
UIViewControllerBase controllerCustom screens
UINavigationControllerStack navigationHierarchical flow
UITabBarControllerTab-basedMain sections
UISplitViewControllerMaster-detailiPad layouts
UIPageViewControllerPage swipingOnboarding

Auto Layout

Constraint TypeDescription
Leading/TrailingHorizontal edges (respects RTL)
Top/BottomVertical edges
CenterX/CenterYCenter alignment
Width/HeightSize constraints
Aspect RatioProportional sizing

Table & Collection Views

ComponentPurpose
UITableViewVertical scrolling lists
UICollectionViewFlexible grid layouts
DiffableDataSourceAutomatic diffing (iOS 13+)
CompositionalLayoutComplex layouts (iOS 13+)

Code Examples

Programmatic View Controller

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
    }
}

Modern Collection View with 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)
    }
}

Custom UIView with Intrinsic Size

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()
    }
}

Troubleshooting

Common Issues

IssueCauseSolution
"Unable to simultaneously satisfy constraints"Conflicting constraintsLower priority on flexible constraints
Cell not appearingMissing registrationUse CellRegistration or register before dequeue
Keyboard covers text fieldNo keyboard handlingObserve keyboard notifications
Content compressedMissing hugging prioritySet content hugging priority higher
View not responding to touchesOverlapping viewsCheck view hierarchy, userInteractionEnabled

Debug Commands

// 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 Rules

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

Usage

Skill("swift-uikit")

Related Skills

  • swift-ios-basics - iOS fundamentals
  • swift-swiftui - Modern alternative
  • swift-architecture - App architecture

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

swift-macos

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

swift-architecture

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

swift-spm

No summary provided by upstream source.

Repository SourceNeeds Review
swift-uikit | V50.AI