Snap 0.9.2

Snap 0.9.2

测试测试版
语言语言 SwiftSwift
许可证 MIT
发布最后发布2015年3月
SPM支持SPM

Robert Payne 维护。



Snap 0.9.2

Snap是一个轻量级的布局框架,它用更简洁的语法包装AutoLayout。Snap拥有自己的布局DSL(领域特定语言),提供了一种连续描述NSLayoutConstraints的方法,从而使得布局代码更加简洁和易于阅读。Snap支持iOS和OS X。

Snap使用了Swift独有的特性,如函数重载,因此无法从Objective-C中使用。正因为如此,我们选择了将Masonry的 mas_ 前缀互换为 snp_,这样您可以在同一个项目中同时使用Masonry和Snap。

要求

  • iOS 7.0+ / Mac OS X 10.9+
  • Xcode 6.1

安装

嵌入式框架需要至少iOS 8或OS X Mavericks的部署目标。

手动安装

如果您不希望使用上述任一依赖管理工具,可以使用以下命令将Snap手动集成到项目中。

嵌入式框架

  • 通过在终端打开,并在顶级项目目录中执行以下命令将Snap作为 子模块 添加:
$ git submodule add https://github.com/Masonry/Snap.git
  • 打开 Snap 文件夹,并将 Snap.xcodeproj 拖到应用程序项目的文件导航器中。
  • 在Xcode中,通过点击蓝色的项目图标,然后选择侧边栏中的“targets”下的应用程序目标来导航到目标配置窗口。
  • 确保Snap.framework的部署目标与应用程序目标的部署目标相匹配。
  • 在该窗口的顶部工具栏中,打开“Build Phases”面板。
  • 展开“Target Dependencies”组,并添加 Snap.framework.
  • 点击面板左上角的 + 按钮,并选择“New Copy Files Phase”。将此新阶段重命名为“Copy Frameworks”,将“Destination”设置为“Frameworks”,并添加 Snap.framework.

NSLayoutConstraints有什么问题?

Auto Layout是组织和管理视图的强大而灵活的方式,但在代码中创建约束既冗长又不清晰。想象一个简单的例子,您希望有一个视图填满其父视图,但在每边缩进10像素:

let superview = self;

let view1 = UIView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.greenColor()
superview.addSubview(view1)

let padding = UIEdgeInsetsMake(10, 10, 10, 10)

superview.addConstraints([
  NSLayoutConstraint(
    item: view1,
    attribute: NSLayoutAttribute.Top,
    relatedBy: NSLayoutRelation.Equal,
    toItem: superview,
    attribute: NSLayoutAttribute.Top,
    multiplier: 1.0,
    constant: padding.top
  ),
  NSLayoutConstraint(
    item: view1,
    attribute: NSLayoutAttribute.Left,
    relatedBy: NSLayoutRelation.Equal,
    toItem: superview,
    attribute: NSLayoutAttribute.Left,
    multiplier: 1.0,
    constant: padding.left
  ),
  NSLayoutConstraint(
    item: view1,
    attribute: NSLayoutAttribute.Bottom,
    relatedBy: NSLayoutRelation.Equal,
    toItem: superview,
    attribute: NSLayoutAttribute.Bottom,
    multiplier: 1.0,
    constant: -padding.bottom
  ),
  NSLayoutConstraint(
    item: view1,
    attribute: NSLayoutAttribute.Right,
    relatedBy: NSLayoutRelation.Equal,
    toItem: superview,
    attribute: NSLayoutAttribute.Right,
    multiplier: 1.0,
    constant: -padding.right
  )
])

即使在如此简单的示例中,所需的代码也已经相当冗长,当你有超过 2 或 3 个视图时,代码很快就会变得难以阅读。另一个选择是使用视觉格式语言(VFL),它比前者稍微简短一些。然而,ASCII 类型的语法也有其自身的问题,并且由于 NSLayoutConstraint.constraintsWithVisualFormat 返回一个数组,这使得它稍微难以动画。

准备与你的创造者见面!

下面是使用 ConstraintMaker 创建的相同约束

let padding = UIEdgeInsetsMake(10, 10, 10, 10)

view1.snp_makeConstraints { make in
  make.top.equalTo(superview.snp_top).with.offset(padding.top) // with is an optional semantic filler
  make.left.equalTo(superview.snp_left).with.offset(padding.left)
  make.bottom.equalTo(superview.snp_bottom).with.offset(-padding.bottom)
  make.right.equalTo(superview.snp_right).with.offset(-padding.right)
}

或者更加简洁

view1.snp_makeConstraints { make in
  make.edges.equalTo(superview).with.insets(padding)
  return // this return is a fix for implicit returns in Swift and is only required for single line constraints
}

请注意,在第一个示例中,我们必须将约束添加到父视图 superview.addConstraints。然而,Snap 会自动将约束添加到相应的视图。

Snap 还会为你调用 view1.setTranslatesAutoresizingMaskIntoConstraints(false)

并不是所有事物都是相等的

.equalTo 等同于 NSLayoutRelation.Equal

.lessThanOrEqualTo 等同于 NSLayoutRelation.LessThanOrEqual

.greaterThanOrEqualTo 等同于 NSLayoutRelation.GreaterThanOrEqual

这三个相等约束接受一个参数,可以是以下任何一种

1. 视图属性

make.centerX.lessThanOrEqualTo(view2.snp_left)
视图属性 NSLayoutAttribute
view.snp_left NSLayoutAttribute.Left
view.snp_right NSLayoutAttribute.Right
view.snp_top NSLayoutAttribute.Top
view.snp_bottom NSLayoutAttribute.Bottom
view.snp_leading NSLayoutAttribute.Leading
view.snp_trailing NSLayoutAttribute.Trailing
view.snp_width NSLayoutAttribute.Width
view.snp_height NSLayoutAttribute.Height
view.snp_centerX NSLayoutAttribute.CenterX
view.snp_centerY NSLayoutAttribute.CenterY
view.snp_baseline NSLayoutAttribute.Baseline

2. UIView/NSView

如果你想使视图的 left 大于或等于标签的 left

// these two constraints are exactly the same
make.left.greaterThanOrEqualTo(label)
make.left.greaterThanOrEqualTo(label.snp_left)

3. 精确检查

自动布局允许将宽度和高度设置为常量值。如果你想要设置视图的宽度和高度具有最小值和最大值,你可以在相等块中传递一个原始值

// width >= 200 && width <= 400
make.width.greaterThanOrEqualTo(200)
make.width.lessThanOrEqualTo(400)

然而,自动布局不允许将左、右、中心等对齐属性设置为常量值。因此,如果你为这些属性传递了一个原始值,Snap 会将这些属性转换为相对父视图的约束,即

// creates view.left <= view.superview.left + 10
make.left.lessThanOrEqualTo(10)

你还可以使用其他原始值和结构体来构建你的约束,如下所示

make.top.equalTo(42)
make.height.equalTo(20)
make.size.equalTo(CGSizeMake(50, 100))
make.edges.equalTo(UIEdgeInsetsMake(10, 0, 10, 0))
make.left.equalTo(view).offset(UIEdgeInsetsMake(10, 0, 10, 0))

学习优先级知识

.prority 允许你指定精确的优先级

.priorityHigh 等同于 UILayoutPriority.DefaultHigh

.priorityMedium 处于高新与低之间

.priorityLow 等同于 UILayoutPriority.DefaultLow

优先级可以添加到约束链的末尾,如下所示

make.left.greaterThanOrEqualTo(label.snp_left).with.priorityLow();

make.top.equalTo(label.snp_top).with.priority(600);

组合,组合,组合

Snap 还提供了一些便利的方法,可以在一次操作中创建多个约束。

边缘

// make top, left, bottom, right equal view2
make.edges.equalTo(view2);

// make top = superview.top + 5, left = superview.left + 10,
//      bottom = superview.bottom - 15, right = superview.right - 20
make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20))

大小

// make width and height greater than or equal to titleLabel
make.size.greaterThanOrEqualTo(titleLabel)

// make width = superview.width + 100, height = superview.height - 50
make.size.equalTo(superview).offset(CGSizeMake(100, -50))

中心

// make centerX and centerY = button1
make.center.equalTo(button1)

// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).offset(CGPointMake(-5, 10))

你可以链式调用视图属性以增强可读性

// All edges but the top should equal those of the superview
make.left.right.and.bottom.equalTo(superview)
make.top.equalTo(otherView)

紧紧抓住不要放手

有时你需要修改现有的约束以便进行动画或移除/替换约束。在 Snap 中,更新约束有几种不同的方法。

1. 参考资料

您可以通过将约束构建表达式的结果分配给局部变量或类属性来保留特定约束的引用。您还可以通过将它们存储在数组中来引用多个约束。

var topConstraint: Constraint? = nil

...

// when making constraints
view1.snp_makeConstraints { make in
  self.topConstraint = make.top.equalTo(superview).with.offset(padding.top)
  make.left.equalTo(superview).with.offset(padding.left)
}

...
// then later you can call
self.topConstraint.uninstall()

2. snp_remakeConstraints

snp_remakeConstraintssnp_addConstraints 类似,但首先会删除 Snap 安装的所有现有约束。

func changeButtonPosition() {
  self.button.snp_remakeConstraints { make in 
    make.size.equalTo(self.buttonSize)

    if topLeft {
      make.top.left.equalTo(10)
    } else {
      make.bottom.equalTo(self.view).offset(-10)
      make.right.equalTo(self.view).offset(-10)
    }
  }
}

代码片段

将包含的代码片段复制到 ~/Library/Developer/Xcode/UserData/CodeSnippets,以您的 snap 关闭编写的闪电速度!

snp_make -> <view>.snp_addConstraints { make in <code> }

snp_remake -> <view>.snp_remakeConstraints { make in <code> }

待办事项

  • 视觉效果
  • 示例项目
  • 测试