利用Auto Layout打造弹性布局——iOS项目推荐

利用Auto Layout打造弹性布局——iOS项目推荐

效果预览

看到上面的动态效果了吗?这是一款简单而有趣的iOS应用效果。利用Auto Layout,实现起来非常容易。今天我将向你介绍如何构建这个效果,即使你是Auto Layout的新手,也能快速上手。

如果你希望跟随教程实践,可以克隆项目到初始状态,然后随着阅读逐步实现效果:

git clone https://github.com/TwoLivesLeft/StretchyLayout.git
cd StretchyLayout
git checkout Step-1

以下是我们的实现步骤:

  1. 创建基础非弹性应用
  2. 修改视图层次以添加必要的约束,使它变得有弹性
  3. 对应用进行优化,提升用户体验

非弹性版应用

初始视图层次

这是基础版本的应用视图结构。主要包含三个部分:头部UIImageView,文本容器和长UILabel。红色线条代表了Auto Layout的约束,还有一个UIScrollView以及视图控制器的根视图。

我们将使用名为SnapKit的框架来构建这个例子。SnapKit是iOS上的一个简单框架,它使得Apple的Auto Layout API更加易用。使用它,编程体验将更加愉快。

大部分代码位于StretchyViewController类的viewDidLoad中。以下展示了如何设置初始约束:

首先声明私有成员变量:

private let scrollView = UIScrollView()
private let infoText = UILabel()
private let imageView = UIImageView()

然后在视图控制器的视图中添加了一个滚动视图,接着是图像和文本视图(还有个背景视图,提供红色背景)。

// 将滚动视图的边缘与视图控制器的视图对齐
scrollView.snp.makeConstraints { make in
    make.edges.equalTo(view)
}

// 图像视图的顶部与滚动视图对齐,左侧和右侧与视图控制器的视图对齐
// 使用宽高比约束,高度为其宽度的70%
imageView.snp.makeConstraints { make in
    make.top.equalTo(scrollView)
    make.left.right.equalTo(view)
    make.height.equalTo(imageView.snp.width).multipliedBy(0.7)
}

// 文本容器的顶部与图像视图底部对齐,左侧和右侧与视图控制器的视图对齐,底部与滚动视图底部对齐
textContainer.snp.makeConstraints { make in
    make.top.equalTo(imageView.snp.bottom)
    make.left.right.equalTo(view)
    make.bottom.equalTo(scrollView)
}

// 文本的边缘与文本容器对齐,留出14点的内边距
infoText.snp.makeConstraints { make in
    make.edges.equalTo(textContainer).inset(14)
}

注:想获取此阶段的代码,请执行git checkout Step-1

简短的插曲:关于SnapKit

注意到我们在代码中使用了SnapKit。这是一个很棒的工具,下面是一个简单的介绍:

只需访问任何UIViewsnp成员对象,即可调用makeConstraints方法,传递一个闭包作为参数,闭包接收一个ConstraintMaker对象(这里称为make)。

然后你可以通过make对象将一个视图的边缘或锚点绑定到其他视图、布局指南或常量。

myView.snp.makeConstraints {
    make in

    make.edges.equalTo(view)
}

这会将myView的边缘与view的边缘对齐。

简洁且可读。强烈建议你使用SnapKit代替原生的Auto Layout API

塑造弹性效果

我们要如何从普通视图转为这样的效果呢?

对比动画

关键在于,无论视图是否是兄弟关系,只要它们有一个共同祖先,Auto Layout都能解决约束。而且,滚动视图内的视图可以与滚动视图外的视图建立约束。这就是我们实现弹性效果的方式。

弹性视图层次

在上述图中,亮红色线表示约束。请注意,现在图像视图的顶部被固定到了最外层视图的顶部,但其底部仍与图片容器视图的底部对齐。这意味着当滚动视图向下滚动时,图像视图会拉伸以满足其约束。

第一步,我们将UIImageView替换为空的容器视图。

let imageContainer = UIView()
imageContainer.backgroundColor = .darkGray
scrollView.addSubview(imageContainer)

imageContainer.snp.makeConstraints { make in
    make.top.equalTo(scrollView)
    make.left.right.equalTo(view)
    make.height.equalTo(imageContainer.snp.width).multipliedBy(0.7)
}

然后,我们在滚动视图内添加图像视图,并将其顶部与视图控制器的视图对齐,而不是滚动视图的顶部(刚刚添加的容器视图是与滚动视图的顶部对齐的)。

scrollView.addSubview(imageView)

imageView.snp.makeConstraints { make in
    make.left.right.equalTo(imageContainer)

    // 这是关键行!
    make.top.equalTo(view)
    make.bottom.equalTo(imageContainer.snp.bottom)
}

如上所示,这两行代码实现了所需效果。图像容器视图的滚动行为与非弹性应用相同。但我们将实际的图像视图放置在其上方,将其底部与容器视图的底部对齐,顶部则固定在视图控制器视图的顶部。

由于设置了imageView.contentMode = .scaleAspectFill,所以在滚动视图下拉时,图像内容会在图像视图内部等比例放大。

注:要获得此阶段的代码,请执行git checkout Step-2

但是有个小问题

如果你运行这段代码,用手指滑动屏幕会产生预期的效果:图像会随手势缩放并反弹。但如果你尝试向上滚动以阅读文本,你会发现无法滚动。

滚动bug

为什么呢?

当我们向上滚动时,我们实际上是在压缩UIImageView,使其高度变为零。它的顶部必须等于视图的顶部,底部必须等于文本容器的顶部。所以,尽管滚动视图仍在“滚动”,但由于文本容器紧贴着图像视图,图像视图拒绝超出视图的顶部,导致滚动无效。

Auto Layout从技术角度解决了我们的约束,但这不是我们想要的结果。

解决问题

我们需要更改图像视图的约束方式。修改后的代码如下:

imageView.snp.makeConstraints { make in
    make.left.right.equalTo(imageContainer)

    // 注意优先级
    make.top.equalTo(view).priority(.high)

    // 我们还增加了一个高度约束
    make.height.greaterThanOrEqualTo(imageContainer.snp.height).priority(.required)

    // 保持底部约束
    make.bottom.equalTo(imageContainer.snp.bottom)
}

现在我们有了顶部约束、底部约束和高度约束。这是Auto Layout的一个强大之处:我们可以有冲突的约束,系统会按优先级顺序打破约束。这就是我们期望的效果。

首先,我们保留原始的约束:图像视图的顶部固定在视图的顶部,赋予其.high优先级。

然后,我们添加额外的约束:图像的高度必须大于或等于图像容器的高度(记住,图像容器有一个宽高比约束)。这个约束的优先级是.required

因此,当我们向上滚动时会发生什么呢?

由于图像的高度约束优先级更高,Auto Layout会打破优先级最低的约束以解决问题。这样,滚动行为就会恢复正常,让我们能够向上滚动并阅读文本。

(另外一种做法是移除高度约束,只将顶部约束优先级设为.high。这会导致iOS在压缩图像视图至零高度时依然能滚动。结合.scaleAspectFill的内容模式,可以创建类似偏移效果。试试看,你可能会更喜欢这种感觉。)

注:要获得此阶段的代码,请执行git checkout Step-3

细节优化

最后,我们还需要处理三个问题,让应用看起来更专业。

  1. 防止文本过度滚动
  2. 尊重安全区域
  3. 滚动视图自适应iPhone X底部指示器

对于第一点,你可以在滚动超出了视图底部时,使文本背后的背景视图扩展出来。详情请参考代码,实现原理与图像视图相同。

注:要获得此阶段的代码,请执行git checkout Step-4

对于第二点,我们希望在iPhone X上文本不覆盖home指示器。为了处理底部的安全区域,我们可以利用iOS 11新增的safeAreaInsets属性。同时,我们也需要手动调整滚动视图的滚动范围。

项目的特点总结如下:

  1. 简单易懂:通过清晰的步骤和SnapKit的易用性,开发者可以轻松理解并实现弹性布局。
  2. 充分利用Auto Layout:通过动态调整约束优先级,实现了滚动时图像和文本的弹性效果。
  3. 兼容性好:考虑了iPhone X的安全区域,确保良好的用户体验。
  4. 实战性强:不仅提供了代码示例,还允许用户在每个步骤中自己动手实践,加深理解和记忆。

立即尝试并加入这个项目,一起探索Auto Layout的无限可能吧!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋海翌Daley

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值