CompositionalLayoutDSL

CompositionalLayoutDSL 是一个 Swift 库。它可以更轻松地为集合视图创建组合布局。


要求

CompositionalLayoutDSL 使用 Swift 5 编写。兼容 iOS 13.0+、tvOS 13.0+ 和 macOS 10.15+。

文档

可以在这里找到在线文档。

文档可以在本地构建并使用此命令查看

swift package --disable-sandbox preview-documentation --target CompositionalLayoutDSL

开始使用

要查看此库的一些用法,您可以查看

这里有一些布局示例

布局代码的屏幕截图 布局代码

这里有一个来自测试目标的例子:GroupDSLTests.swift(包含相同的布局,没有使用 DSL)

let layout = CompositionalLayout { section, environment in
    Section {
        HGroup {
            Item(width: .fractionalWidth(1 / 3))
                .contentInsets(trailing: 4)
            VGroup(count: 2) { Item() }
                .width(.fractionalWidth(1 / 3))
                .interItemSpacing(.fixed(8))
                .contentInsets(horizontal: 4)
            VGroup(count: 3) { Item() }
                .width(.fractionalWidth(1 / 3))
                .interItemSpacing(.fixed(8))
                .contentInsets(leading: 4)
        }
        .height(.absolute(100))
        .contentInsets(horizontal: 16)
    }
    .interGroupSpacing(8)
}
.interSectionSpacing(8)

// Apply to a collection view
collectionView.setCollectionViewLayout(layout, animated: false)
// or
collectionView.collectionViewLayout = LayoutBuilder { layout }

这里有一个来自示例项目的例子:GettingStartedCompositionalLayout.swift

collectionView.collectionViewLayout = LayoutBuilder {
    Section {
        VGroup(count: 1) { Item() }
            .height(.fractionalWidth(0.3))
            .width(.fractionalWidth(0.3))
            .interItemSpacing(.fixed(8))
    }
    .interGroupSpacing(8)
    .contentInsets(horizontal: 16, vertical: 8)
    .orthogonalScrollingBehavior(.continuous)
    .supplementariesFollowContentInsets(false)
    .boundarySupplementaryItems {
        BoundarySupplementaryItem(elementKind: UICollectionView.elementKindSectionHeader)
            .height(.absolute(30))
            .alignment(.top)
            .pinToVisibleBounds(true)
    }
}

安装

Cocoapods

要使用 CocoaPods 将 CompositionalLayoutDSL 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它

pod 'CompositionalLayoutDSL', '~> 0.2.0'

Swift Package Manager

CompositionalLayoutDSL 可以作为 Swift Package 与 Xcode 11 或更高版本一起安装。要安装它,请使用 Xcode 添加一个包或向您的 Package.swift 文件添加一个依赖项

.package(url: "https://github.com/faberNovel/CompositionalLayoutDSL", from: "0.2.0")

幕后原理

这里有一些关于这个库如何工作的解释,它可以分为三个部分:核心块的角色、修改器如何工作以及如何处理到 UIKit 世界的转换

核心结构体

这个库包含所有用于创建组合布局的核心结构体,这里是详尽的列表

这些构建块中的每一个都符合它们各自的公共协议,并处理与其关联的 UIKit 对象的不可变属性。

例如,SupplementaryItem 符合 LayoutSupplementaryItem 并处理 NSCollectionLayoutSupplementaryItem 的不可变属性,这些属性是:layoutSizeelementKindcontainerAnchoritemAnchor

这些不可变属性只能在这些核心结构体上更改,并且不能全局地在 LayoutSupplementaryItem 上使用。所有核心结构体都是如此。

修改器

UIKit 对象的其他可变属性由 Layout... 协议的扩展处理。这里有一些例子:contentInset(_:)edgeSpacing(_:)zIndex(_:)interItemSpacing(_:)scrollDirection(_:)。 这些可变值的更改是通过修改器完成的,修改器是内部结构体(例如,ValueModifiedLayoutItem)。由于这些方法通过扩展 Layout... 协议提供,因此它们可用于库之外的自定义元素。

需要注意的是,一旦您应用了可变属性的修改器,您就不再拥有 Item,而是拥有 LayoutItem,因此之后将无法更改不可变的值。

DSL 到 UIKit 的转换

最后,一旦我们组合了核心结构体和修改器,最后一步就是将 Layout... 转换为 UIKit 世界。 这是通过构建器完成的,它们都以类似的方式工作。 作为一个例子,这里 ItemBuilder 如何工作

⚠️警告⚠️

这意味着只有内部结构体可以转换为 UIKit 对象,如果您尝试定义自定义 LayoutItem 并像内部完成的那样编写 var layoutItem: LayoutItem { self },它将在 ItemBuilder 内部导致无限循环。

该库的用户需要将其自定义布局基于此库提供的核心结构体。

鸣谢

CompositionalLayoutDSL 由 Fabernovel 拥有和维护。 您可以在 Twitter 上关注我们:@Fabernovel

许可证

CompositionalLayoutDSL 在 MIT 许可证下可用。 有关更多信息,请参见 LICENSE 文件。