AnchorKit 3.0.3

AnchorKit 3.0.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布Apr 2024
SPM支持 SPM

Eddie KaigerJames RichardJace Conflenti 维护。



AnchorKit 3.0.3

  • 作者
  • Jace Conflenti

AnchorKit

Swift Version Carthage compatible CocoaPods Compatible Platform Build Status

AnchorKit 使用锚点创建布局提供了一种简单直观的方法。

快速开始

以下是示例代码

// Multiple constraints on one line
myView.constrain(.leading, .top, .trailing, to: anotherView)

// One-line edge constraints with insets
myView.constrainEdges(to: anotherView).inset(10)
myView.constrainEdges(to: anotherView).insetVertical(20).insetHorizontal(30)

// Set height/width equal to a constant
myView.constrain(.height, .width, toConstant: 200)
myView.constrainWidth(to: 42)

// Set the height/width equal to a CGSize
myView.constrain(to: CGSize(width: 100, height: 200))

// Set offset (constant)
myView.constrain(.leading, to: .trailing, of: anotherView).offset(20)

// Set insets
myView.constrain(.leading, .trailing, to: anotherView).inset(24)

// Set the relation and multiplier
myView.constrain(.height, relation: .lessThanOrEqual, to: anotherView, multiplier: 1.6)

// Set the priority
myView.constrain(.centerY, to: anotherView, priority: .high).offset(-15)

// Easily center items
myView.constrainCenter(to: anotherView)

// Return value for single constraint is NSLayoutConstraint
let bottomConstraint = myView.constrain(.bottom, to: .top, of: anotherView.layoutMarginsGuide)

// Return value for multiple constraints is [NSLayoutConstraint]
let topAndSideConstraints = myView.constrain(.leading, .trailing, .top, to: anotherView)

特性

  • 简单、直观、Swifty 语法
  • 不再需要每行都写 isActive = true约束默认激活返回值🎉)
  • 自动处理 translatesAutoresizingMaskIntoConstraints = false
  • 布局指南和视图 一起工作
  • 在所有支持 AutoLayout 约束的 3 个平台(iOS、macOS、tvOS)上工作
  • 不需要处理专有的类;返回值是 NSLayoutConstraint[NSLayoutConstraint]
  • 使用任何数字类型(IntDoubleFloat 等),无需转换为 CGFloat

需求

  • iOS 9.0+, macOS 10.12+, tvOS 9.0+
  • Swift 3.1+
  • Xcode 8+

安装

CocoaPods

pod 'AnchorKit'

Carthage

github "Weebly/AnchorKit"

Swift Package Manager

package(url: "https://github.com/Weebly/AnchorKit.git", .from("2.3.0"))

使用

Anchor 枚举

AnchorKit 的 API 主要基于表示视图和布局指南上不同锚定类型的枚举。

public enum Anchor {
    case leading
    case trailing
    case left
    case right
    case top
    case bottom
    case width
    case height
    case centerX
    case centerY

    // These two are only available on views, not layout guides.
    case firstBaseline
    case lastBaseline
}

自动布局定义了 3 种类型的锚,并且您只能将锚定关系限制在同一个组内的其它锚上。

  • 横轴锚点leadingtrailingleftrightcenterX
  • Y轴锚点: top, bottom, centerY, firstBaseline, lastBaseline
  • 尺寸锚点: width, height

在内部,这些锚点都映射到您正在约束的视图或布局指南上的实际NSLayoutAnchor

创建约束

Anchorable 协议

AnchorKit 同时支持布局指南和视图。为了统一这两个,我们使用一个名为 Anchorable 的协议。视图遵守另一个协议,ViewAnchorable,这使得它们可以使用基线锚点。以下文档中的“项”一词指的是视图和布局指南。

锚点至项目约束

将一个项目的锚点约束到另一个项目的对应锚点上。

myView.constrain(.leading, .trailing, .top, to: anotherView)

使用单个锚点调用此方法将隐式返回 NSLayoutConstraint。否则,返回类型是 [NSLayoutConstraint]。以下显示了这些方法的完整签名。

// Single constraint
@discardableResult
public func constrain<AnchorableType: Anchorable>(_ anchor: Anchor, relation: NSLayoutRelation = .equal, to item: AnchorableType, multiplier: CGFloatRepresentable = 1, priority: LayoutPriority = .required) -> NSLayoutConstraint

// Multiple constraints
@discardableResult
public func constrain<AnchorableType: Anchorable>(_ anchors: Anchor..., relation: NSLayoutRelation = .equal, to item: AnchorableType, multiplier: CGFloatRepresentable = 1, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

锚点至锚点约束

将一个项目的锚点约束到另一个项目的锚点上。

myView.constrain(.top, to: .bottom, of: anotherView.readableContentGuide)

此方法只支持创建单个约束。

@discardableResult
public func constrain<AnchorableType: Anchorable>(_ anchor: Anchor, relation: NSLayoutRelation = .equal, to otherAnchor: Anchor, of item: AnchorableType, multiplier: CGFloatRepresentable = 1, priority: LayoutPriority = .required) -> NSLayoutConstraint

锚点至常量约束

将项的锚点约束到常量。这对于 widthheight 锚点特别有用(且更易读)。

myView.constrain(.height, toConstant: 200)
myBoxView.constrain(.width, .height, toConstant: 50) // Creates a box

// Even easier:
myView.constrainHeight(to: 42)
myView.constrainWidth(to: 60)

使用单个锚点调用此方法将隐式返回 NSLayoutConstraint。否则,返回类型是 [NSLayoutConstraint]。以下显示了这些方法的完整签名。

// Single constraint
@discardableResult
public func constrain(_ anchor: Anchor, relation: NSLayoutRelation = .equal, toConstant constant: CGFloatRepresentable, priority: LayoutPriority = .required) -> NSLayoutConstraint

// Multiple constraints
@discardableResult
public func constrain(_ anchors: Anchor..., relation: NSLayoutRelation = .equal, toConstant constant: CGFloatRepresentable, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

此方法也可以应用于具有除 widthheight 之外锚点的项目。生成的行为与将锚点约束到视图的 superview(或布局指南的 owningView)上的对应锚点等效。因此,myView.constrain(.leading, toConstant: 10) 等同于 myView.constrain(.leading, to: myView.superview!).offset(10)

约束到边缘

将当前项目的边缘约束到另一个项目。

myView.constrainEdges(to: anotherView)

这只是一个用来约束 leadingtrailingtopbottom 锚点的便利方法。如果您想添加一个不同于 .equalrelation 到约束,有一个相当于的独立方法。

@discardableResult
public func constrainEdges<AnchorableType: Anchorable>(to item: AnchorableType, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

// With a relation other than .equal
@discardableResult
public func constrainEdges<AnchorableType: Anchorable>(_ relation: NSLayoutRelation, to item: AnchorableType, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

约束到中心

将当前项目的中心约束到另一个项目。

myView.constrainCenter(to: anotherView)

这是一个用来约束 centerXcenterY 锚点的便利方法。如果您想添加一个不同于 .equalrelation 到约束,有一个相当于的独立方法。

@discardableResult
public func constrainCenter<AnchorableType: Anchorable>(to item: AnchorableType, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

// With a relation other than .equal
@discardableResult
public func constrainCenter<AnchorableType: Anchorable>(_ relation: NSLayoutRelation, to item: AnchorableType, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

约束到大小

将项目的宽度约束到特定 CGSize

myView.constrain(to: CGSize(width: 10, height: 20))

这是一个用来设置 widthheight 锚点到相应的 CGSize 宽度和高度的便利方法。如果您想添加一个不同于 .equalrelation 到约束,有一个相当于的独立方法。

@discardableResult
public func constrain(to size: CGSize, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

@discardableResult
public func constrain(_ relation: NSLayoutRelation, to size: CGSize, priority: LayoutPriority = .required) -> [NSLayoutConstraint]

对于视图,由于宽度和高度约束属于视图本身,您可以直接从视图更改这些约束。

myView.updateSize(newSize)
myView2.updateWidth(100)
myView3.updateHeight(200)

约束到 UIViewController 的 topLayoutGuidebottomLayoutGuide

UIViewController 上的 topLayoutGuidebottomLayoutGuide 属性的类型是 UILayoutSupport,这是一个协议。就像约束到任何其他项目一样,将这些约束到它们上面。

请注意,这些上仅有的可用锚点是 heighttopbottom

myView.constrain(.top, to: .bottom, of: topLayoutGuide).offset(10)
otherView.constrain(.height, to: bottomLayoutGuide)

这些方法的签名与锚到锚和锚到项目的签名相同,只是第二个条目具有类型 UILayoutSupport

CGFloatRepresentable 协议

本协议允许您为约束偏移量、内边距和乘数使用任何数字类型,而无需将所有值转换为 CGFloat

public protocol CGFloatRepresentable {
    var cgFloatValue: CGFloat { get }
}

以下类型采用此协议

  • IntInt8Int16Int32Int64
  • UIntUInt8UInt16UInt32UInt64
  • Double
  • FloatFloat80
  • CGFloat
  • NSNumber

偏移量和内边距

要设置约束上的常量,AnchorKit 使用 偏移量内边距。偏移量的行为与 NSLayoutConstraint 上的 constant 相当。但是,内边距却会对 trailingrightbottomlastBaseline 锚的常量求反,并对所有其他锚按正常方式行为。

// The top of bottomView will be 20 points below the top of topView
bottomView.constrain(.top, of: topView).offset(20)

// The innerView will be "inside" the outerView, with 10 points of padding on the sides
innerView.constrain(.leading, .trailing, to: outerView).inset(10)

如您在第二个示例中注意到的,offset(_:)inset(_:) 既可以用于单个约束,也可以用于一系列约束。

在更新约束时,为了遵循 Swift 命名约定,AnchorKit 还提供了 updateOffset(_:)updateInset(_:) 方法。

您还可以使用 UIEdgeInsets(或者在 macOS 上的 EdgeInsets)来设置内边距。内边距将应用于相应的约束。

innerView.constrainEdges(to: outerView).inset(UIEdgeInsets(top: 10, left: 12, bottom: 14, right: 16))

对于多个约束,还可以只设置水平/垂直内边距,如下所示

// The innerView will have an inset of 10 on the top and bottom sides and an inset of 20 on the leading and trailing sides
innerView.constrainEdges(to: outerView).insetVertical(10).insetHorizontal(20)`

当更新水平/垂直内边距时,使用 updateHorizontalInsets(_:)updateVerticalInsets(_:)

布局优先级

要设置约束的优先级,AnchorKit 提供了一个名为 LayoutPriority 的枚举。

public enum LayoutPriority: RawRepresentable {
    case low        // Priority: 250
    case medium     // Priority: 500
    case high       // Priority: 750
    case required   // Priority: 1000
    case custom(Float)
}

所有约束创建方法都有一个默认优先级 required,但在需要时可以设置自己的优先级。

myView.constrain(.centerX, to: anotherView, priority: .medium)

对于复杂的布局,有时您可能只想为某个约束设置 稍微高一点 的优先级。好消息是您可以使用加法和减法运算符与布局优先级一起使用。

myView.constrain(.left, to: anotherView, priority: .low + 1) // Priority = 251

您可以使用 layoutPriority 扩展方法获取/设置 NSLayoutConstraint 的布局优先级。

let topConstraint = myView.constrain(.top, to: anotherView, priority: .medium)
topConstraint.layoutPriority = .high

最后,使用布局优先级设置您的内容压缩抵抗和内容抓紧。

myView.hug(with: .low, for: .vertical)
myView.resistCompression(with: .high, for: .horizontal)

其他好东西

激活 & 停用

AnchorKit 限制条件默认处于激活状态。然而,您也可以停用限制条件并在同一行捕获它们

let centerYConstraint = myView.constraint(.centerY, to: anotherView).deactivate()
// ...
centerYConstraint.activate()

这些方法同样适用于一系列限制条件。

处理iOS 11系统间隔约束

在iOS 11和tvOS 11中,UIKit通过使用系统定义间距的方法,如constraintEqualToSystemSpacingAfter(_:multiplier:),提供了一种新的方式来定义限制条件。当对新的安全区域布局指南进行限制时,这些方法非常有用,这是在UIView上找到的,这是现在推荐的API,而不是在UIViewController上使用topLayoutGuidebottomLayoutGuide(现在已被废弃)。

AnchorKit提供了系统间距限制的高级别方法

myView.constrainUsingSystemSpacing(.top, .below, .bottom, of: anotherView.safeAreaLayoutGuide)
myView.constrainUsingSystemSpacing(.leading, .after, .trailing, of: anotherView.safeAreaLayoutGuide)

此方法的全局签名如下

@discardableResult
public func constrainUsingSystemSpacing<AnchorableType: Anchorable>(_ anchor: Anchor, relation: Relation = .equal, _ position: SystemSpacingPosition, _ otherAnchor: Anchor, of item: AnchorableType, multiplier: CGFloatRepresentable = 1, priority: LayoutPriority = .required) -> NSLayoutConstraint

支持

有关问题、支持和建议,请创建一个issue。

许可证

AnchorKit 采用MIT许可证。请参阅LICENSE文件以获取更多信息。