Initial commit: add all skills files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 16:52:49 +08:00
commit 6487becf60
396 changed files with 108871 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
# Layout System
iOS layout system guide covering touch targets, safe areas, UICollectionView, and Compositional Layout.
## Touch Targets
Interactive elements need adequate tap areas. The recommended minimum is 44x44 points.
```swift
let actionButton = UIButton(type: .system)
actionButton.setTitle("Submit", for: .normal)
view.addSubview(actionButton)
actionButton.snp.makeConstraints { make in
make.height.greaterThanOrEqualTo(44)
make.leading.trailing.equalToSuperview().inset(16)
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-16)
}
```
Use 8-point increments for spacing (8, 16, 24, 32, 40, 48) to maintain visual consistency.
## Safe Area
Always constrain content to the safe area to avoid the notch, Dynamic Island, and home indicator.
```swift
class MainViewController: UIViewController {
private let contentStack = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
contentStack.axis = .vertical
contentStack.spacing = 16
view.addSubview(contentStack)
contentStack.snp.makeConstraints { make in
make.top.bottom.equalTo(view.safeAreaLayoutGuide)
make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16)
}
}
}
```
## UICollectionView with Diffable Data Source
```swift
class ItemsViewController: UIViewController {
enum Section { case main }
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
override func viewDidLoad() {
super.viewDidLoad()
setupCollectionView()
configureDataSource()
}
private func setupCollectionView() {
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
config.trailingSwipeActionsConfigurationProvider = { [weak self] indexPath in
self?.makeSwipeActions(for: indexPath)
}
let layout = UICollectionViewCompositionalLayout.list(using: config)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
private func configureDataSource() {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
cell, indexPath, item in
var content = cell.defaultContentConfiguration()
content.text = item.title
content.secondaryText = item.subtitle
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) {
collectionView, indexPath, item in
collectionView.dequeueConfiguredReusableCell(
using: cellRegistration, for: indexPath, item: item
)
}
}
func updateItems(_ items: [Item]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.apply(snapshot)
}
}
```
## Grid Layout
```swift
private func createGridLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/3),
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(1/3)
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
```
## Sectioned List with Headers
```swift
class CategorizedListVC: UIViewController {
enum Section: Hashable {
case favorites, recent, all
}
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
private func setupCollectionView() {
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
config.headerMode = .supplementary
let layout = UICollectionViewCompositionalLayout.list(using: config)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
}
private func configureDataSource() {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
cell, indexPath, item in
var content = cell.defaultContentConfiguration()
content.text = item.title
cell.contentConfiguration = content
}
let headerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(
elementKind: UICollectionView.elementKindSectionHeader
) { [weak self] header, elementKind, indexPath in
guard let section = self?.dataSource.sectionIdentifier(for: indexPath.section) else { return }
var content = header.defaultContentConfiguration()
content.text = self?.title(for: section)
header.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) {
collectionView, indexPath, item in
collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}
dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath)
}
}
func applySnapshot(favorites: [Item], recent: [Item], all: [Item]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
if !favorites.isEmpty {
snapshot.appendSections([.favorites])
snapshot.appendItems(favorites, toSection: .favorites)
}
if !recent.isEmpty {
snapshot.appendSections([.recent])
snapshot.appendItems(recent, toSection: .recent)
}
snapshot.appendSections([.all])
snapshot.appendItems(all, toSection: .all)
dataSource.apply(snapshot)
}
}
```
## Spacing Guidelines
| Spacing | Usage |
|---------|-------|
| 8pt | Compact element spacing |
| 16pt | Standard padding |
| 24pt | Section spacing |
| 32pt | Large section separation |
| 48pt | Screen margins (large screens) |
---
*UIKit and Apple are trademarks of Apple Inc. SnapKit is a trademark of its respective owners.*