当前位置: 首页 > news >正文

Swift-snapKit使用

snapKit的使用注意

SnapKit 是一个优秀的 Swift Auto Layout 库,但在使用中需要注意一些重要事项。以下是详细的使用注意事项:

1. 内存管理 - 避免循环引用

❌ 错误用法:

swift

class ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()let button = UIButton()view.addSubview(button)button.snp.makeConstraints { make in// 这里隐式捕获了 selfmake.center.equalTo(self.view)make.width.equalTo(self.view).multipliedBy(0.5)}}
}

✅ 正确用法:

swift

class ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()let button = UIButton()view.addSubview(button)button.snp.makeConstraints { [weak self] make inguard let self = self else { return }make.center.equalTo(self.view)make.width.equalTo(self.view).multipliedBy(0.5)}}
}

2. 视图层级顺序

❌ 错误用法:

swift

// 先设置约束,后添加到父视图
view.snp.makeConstraints { make inmake.edges.equalToSuperview()
}
parentView.addSubview(view) // 太晚了!

✅ 正确用法:

swift

// 先添加到父视图,再设置约束
parentView.addSubview(view)
view.snp.makeConstraints { make inmake.edges.equalToSuperview()
}

3. 约束更新和重制

更新特定约束:

swift

class CustomView: UIView {var topConstraint: Constraint?func setupConstraints() {self.snp.makeConstraints { make inself.topConstraint = make.top.equalToSuperview().constraintmake.left.right.equalToSuperview()make.height.equalTo(100)}}func updateTopConstraint() {// 更新单个约束self.topConstraint?.update(offset: 20)}
}

重制所有约束:

swift

class CustomView: UIView {func remakeConstraintsForNewLayout() {// 移除所有旧约束,创建新约束self.snp.remakeConstraints { make inmake.edges.equalToSuperview()}}func updateConstraintsForAnimation() {// 更新现有约束self.snp.updateConstraints { make inmake.top.equalToSuperview().offset(50)}}
}

4. 优先级使用

swift

view.snp.makeConstraints { make in// 设置优先级make.width.equalTo(200).priority(.high)make.width.lessThanOrEqualTo(300).priority(.required)make.width.greaterThanOrEqualTo(100).priority(.medium)// 或者使用具体数值make.height.equalTo(100).priority(999)
}

5. 安全区域和边距

❌ 过时用法:

swift

view.snp.makeConstraints { make inmake.top.equalTo(topLayoutGuide.snp.bottom) // iOS 11 之前
}

✅ 现代用法:

swift

view.snp.makeConstraints { make in// 适配安全区域make.top.equalTo(view.safeAreaLayoutGuide.snp.top)make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)// 或者使用 edges 快捷方式make.edges.equalTo(view.safeAreaLayoutGuide)
}

考虑可读边距:

swift

view.snp.makeConstraints { make inmake.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16))
}

6. 性能优化

批量设置约束:

swift

// ❌ 低效:多次布局计算
view1.snp.makeConstraints { $0.top.equalToSuperview() }
view2.snp.makeConstraints { $0.top.equalTo(view1.snp.bottom) }
view3.snp.makeConstraints { $0.top.equalTo(view2.snp.bottom) }// ✅ 高效:一次布局计算
snp.prepareConstraints { view1.snp.makeConstraints { $0.top.equalToSuperview() }view2.snp.makeConstraints { $0.top.equalTo(view1.snp.bottom) }view3.snp.makeConstraints { $0.top.equalTo(view2.snp.bottom) }
}
// 然后调用 layoutIfNeeded()

7. 动画处理

swift

class AnimatedView: UIView {var topOffset: Constraint?func setup() {self.snp.makeConstraints { make inself.topOffset = make.top.equalToSuperview().offset(0).constraintmake.centerX.equalToSuperview()make.width.height.equalTo(100)}}func animate() {// 更新约束self.topOffset?.update(offset: 200)// 执行动画UIView.animate(withDuration: 0.3) {self.superview?.layoutIfNeeded()}}
}

8. 常见约束模式

居中布局:

swift

view.snp.makeConstraints { make inmake.center.equalToSuperview()make.size.equalTo(CGSize(width: 100, height: 100))
}

等分布局:

swift

let views = [view1, view2, view3]
views.forEach { parentView.addSubview($0) }view1.snp.makeConstraints { make inmake.left.top.bottom.equalToSuperview()
}view2.snp.makeConstraints { make inmake.left.equalTo(view1.snp.right)make.top.bottom.equalToSuperview()make.width.equalTo(view1)
}view3.snp.makeConstraints { make inmake.left.equalTo(view2.snp.right)make.right.top.bottom.equalToSuperview()make.width.equalTo(view1)
}

9. 调试技巧

添加标识符(iOS 11+):

swift

view.snp.makeConstraints { make inlet constraint = make.width.equalTo(100).constraintconstraint.identifier = "CustomViewWidthConstraint"
}

检查约束冲突:

swift

override func updateConstraints() {super.updateConstraints()// 检查是否有无法满足的约束if hasAmbiguousLayout {exerciseAmbiguityInLayout()}
}

10. 最佳实践总结

  1. 总是先 addSubview 再设置约束

  2. 使用 [weak self] 避免循环引用

  3. 合理使用 makeConstraintsupdateConstraintsremakeConstraints

  4. 考虑安全区域,特别是 iPhone X 及以上机型

  5. 为复杂动画预先保存约束引用

  6. 使用优先级解决约束冲突

  7. 批量设置约束优化性能

  8. 为重要约束添加标识符便于调试

遵循这些注意事项可以避免常见的 SnapKit 使用陷阱,写出更健壮、易维护的布局代码。

SnapKit 的布局优先级是非常重要的功能,用于处理约束冲突和动态布局。以下是详细的使用指南:

1. 优先级基础用法

内置优先级级别:

swift

view.snp.makeConstraints { make inmake.width.equalTo(200).priority(.high)make.width.greaterThanOrEqualTo(100).priority(.medium)make.width.lessThanOrEqualTo(300).priority(.low)
}// 或者使用具体数值
view.snp.makeConstraints { make inmake.width.equalTo(200).priority(999)make.height.equalTo(100).priority(500)
}

SnapKit 内置优先级常量:

swift

.priority(.required)        // 1000
.priority(.high)            // 750  
.priority(.medium)          // 500
.priority(.low)             // 250
.priority(.fittingSizeLevel) // 50

2. 优先级解决约束冲突

场景:宽度自适应但有最大最小限制

swift

label.snp.makeConstraints { make in// 必需约束:最大宽度不超过屏幕的80%make.width.lessThanOrEqualToSuperview().multipliedBy(0.8).priority(.required)// 高优先级:首选宽度make.width.equalTo(150).priority(.high)// 低优先级:如果内容太多可以超过150make.width.greaterThanOrEqualTo(150).priority(.low)
}

3. 动态调整优先级

保存约束引用并修改优先级:

swift

class CustomView: UIView {var widthConstraint: Constraint?var heightConstraint: Constraint?func setupConstraints() {self.snp.makeConstraints { make inself.widthConstraint = make.width.equalTo(100).priority(.high).constraintself.heightConstraint = make.height.equalTo(100).priority(.high).constraintmake.center.equalToSuperview()}}func makeSizeFlexible() {// 降低优先级,允许压缩self.widthConstraint?.deactivate()self.snp.makeConstraints { make inself.widthConstraint = make.width.equalTo(100).priority(.low).constraint}}
}

4. 条件优先级

根据条件设置不同优先级:

swift

class AdaptiveView: UIView {var isCompact: Bool = falsefunc updateConstraints() {self.snp.remakeConstraints { make inif isCompact {make.width.equalTo(80).priority(.required)make.height.equalTo(40).priority(.required)} else {make.width.equalTo(120).priority(.required)make.height.equalTo(60).priority(.required)}make.center.equalToSuperview()}}
}

5. 多约束竞争场景

按钮组布局示例:

swift

class ButtonGroup: UIView {let button1 = UIButton()let button2 = UIButton()let button3 = UIButton()func setupConstraints() {[button1, button2, button3].forEach { addSubview($0) }button1.snp.makeConstraints { make inmake.left.equalToSuperview()make.top.bottom.equalToSuperview()// 首选宽度,但不是强制的make.width.equalTo(100).priority(.high)}button2.snp.makeConstraints { make inmake.left.equalTo(button1.snp.right)make.top.bottom.equalToSuperview()// 与button1等宽,高优先级make.width.equalTo(button1).priority(.high)}button3.snp.makeConstraints { make inmake.left.equalTo(button2.snp.right)make.right.equalToSuperview()make.top.bottom.equalToSuperview()// 与button1等宽,但优先级较低,可以压缩make.width.equalTo(button1).priority(.medium)}}
}

6. UILabel 多行文本自适应

swift

label.snp.makeConstraints { make in// 必需:最大宽度限制make.width.lessThanOrEqualTo(300).priority(.required)// 高优先级:首选宽度make.width.equalTo(200).priority(.high)// 低优先级:最小宽度保证可读性make.width.greaterThanOrEqualTo(80).priority(.low)// 高度自适应make.height.greaterThanOrEqualTo(40).priority(.required)
}

7. 响应式布局优先级

根据屏幕方向调整:

swift

class ResponsiveView: UIView {var portraitConstraints: [Constraint] = []var landscapeConstraints: [Constraint] = []func setupConstraints() {// 竖屏约束self.snp.makeConstraints { make inportraitConstraints = [make.width.equalToSuperview().priority(.high).constraint,make.height.equalTo(200).priority(.high).constraint]}// 横屏约束(初始不激活)landscapeConstraints = self.snp.prepareConstraints { make inmake.width.equalTo(300).priority(.high).constraintmake.height.equalToSuperview().priority(.high).constraint}}func updateForOrientation(_ isLandscape: Bool) {if isLandscape {portraitConstraints.forEach { $0.deactivate() }landscapeConstraints.forEach { $0.activate() }} else {landscapeConstraints.forEach { $0.deactivate() }portraitConstraints.forEach { $0.activate() }}}
}

8. 复杂布局优先级策略

三栏布局示例:

swift

class ThreeColumnLayout: UIView {let leftView = UIView()let centerView = UIView()let rightView = UIView()func setupConstraints() {[leftView, centerView, rightView].forEach { addSubview($0) }// 左栏:固定宽度,高优先级leftView.snp.makeConstraints { make inmake.left.top.bottom.equalToSuperview()make.width.equalTo(100).priority(.required)}// 右栏:固定宽度,高优先级rightView.snp.makeConstraints { make inmake.right.top.bottom.equalToSuperview()make.width.equalTo(100).priority(.required)}// 中间栏:自适应,但有限制centerView.snp.makeConstraints { make inmake.left.equalTo(leftView.snp.right)make.right.equalTo(rightView.snp.left)make.top.bottom.equalToSuperview()// 最小宽度保证,但优先级较低make.width.greaterThanOrEqualTo(200).priority(.medium)// 首选宽度,但不是强制的make.width.equalTo(300).priority(.low)}}
}

9. 调试优先级问题

添加约束标识符:

swift

view.snp.makeConstraints { make inlet widthConstraint = make.width.equalTo(100).priority(.high).constraintwidthConstraint.identifier = "HighPriorityWidth"let heightConstraint = make.height.equalTo(100).priority(.medium).constraintheightConstraint.identifier = "MediumPriorityHeight"
}

检查激活的约束:

swift

func debugConstraints() {DispatchQueue.main.async {let constraints = self.constraintsfor constraint in constraints {if let identifier = constraint.identifier {print("约束: \(identifier), 优先级: \(constraint.priority.rawValue), 激活: \(constraint.isActive)")}}}
}

10. 最佳实践总结

  1. 合理使用优先级层次.required → .high → .medium → .low

  2. 避免过多 .required 优先级,容易导致约束冲突

  3. 为自适应布局使用 .medium 和 .low 优先级

  4. 保存约束引用用于动态调整

  5. 使用约束标识符便于调试

  6. 考虑使用 UILayoutPriority 自定义数值.priority(UILayoutPriority(800))

  7. 测试不同屏幕尺寸下的优先级表现

  8. 优先保证内容可读性,其次考虑设计精确度

正确使用优先级可以让布局更加灵活和健壮,特别是在处理动态内容和多设备适配时。

http://www.dtcms.com/a/593612.html

相关文章:

  • Hello-Agents第二章深度解析:智能体的进化之路——从符号逻辑到AI原生
  • 51单片机汇编实现DHT11读取温湿度
  • LiveCharts.Wpf 控件的使用
  • 柔性软风管-测量统计一键出量
  • 告别手动录财报!财务报表OCR识别解决方案选型指南
  • (128页PPT)智慧化工厂区一体化管理平台建设方案(附下载方式)
  • jsp网站建设项目实战总结怎么做网站统计
  • 【Rust 探索之旅】Rust 全栈 Web 开发实战:从零构建高性能实时聊天系统
  • 【Rust 探索之旅】Tokio 异步运行时完全指南:深入理解 Rust 异步编程与源码实现
  • 个人网站做经营性crm销售管理系统功能
  • Ubuntu 22.04 Docker 安装指南
  • C++基础语法篇二 ——引用、内联和空指针
  • 有没有做兼职的好网站十堰网络公司排名
  • vscode中claude code插件代理地址设置
  • 网页制作与网站管理在线销售管理系统
  • 如何使用 vxe-table 实现右键菜单异步权限控制
  • 11月10日学习总结--初识numpy
  • 前后端通信加解密(Web Crypto API )
  • 基于数字图像相关(DIC)技术的机械臂自动化焊接残余应力全场变形高精度测量
  • XTOM-TRANSFORM-ROB:面向大尺寸构件的移动式非接触三维扫描与自动化质量检测
  • PyWinInspect:pywinauto 桌面自动化开发伴侣,集成 Inspect 元素检查 + 定位代码自动生成,效率大提升!
  • 个人做什么网站软件技术专升本难吗
  • HarmonyOS:ArkUI栅格布局系统(GridRow/GridCol)
  • 电商设计师常用的网站wordpress 获取分类地址
  • 开放签电子签章系统3.2版本更新内容
  • 电子商务的网站建设过程辽宁沈阳网站建设
  • C++ 设计模式《统计辅助功能》
  • 【技术分享】ComfyUI中protobuf版本兼容性问题的优雅解决方案:猴子补丁实战
  • Redis 高级篇(未完结1/3)
  • 华为OD机试 真题 - 【国际移动用户识别码(IMSI)匹配】 - 双机位A卷 (Python C++ JAVA JS GO)