前言
最近感觉自己总是学习网络相关的, 有点"疲劳"了. 所以今天换个口味, 试着翻译下国外大神的博客. 有不好的地方还请赐教!
正文
先让我们一起看看苹果是如何在系统中使用的.
其中, 控制中心是一个值得关注的示例. 模糊背景为控制中心的操作提供环境 - 虽然控制中心不属于某一个APP, 但它却显示在这些活动APP的上方.
通知中心也使用了该效果, 但是, 这里不是让整个背景都模糊了, 每一个extension或通知都有自己模糊的背景. 这不仅看上去漂亮, 而且使每一个元素都很显眼.
那么如何在自己的APP中再现这些效果呢? 没错, 就是使用iOS内建的UIVisualEffectView! 该篇, 你将学到关于使用"模糊效果"的一切, 以使你的APP更出众.
关于"模糊效果"你需要了解的事实
如何优雅,高效的使用需要一定的技巧. 这里会了解到"模糊效果"使用到的常规算法.
模糊效果是如何工作的
所有的模糊效果都始于一张图片. 为了实现该效果, 你需要对图片的每一个像素应用模糊算法(blurring algorithm), 这样可以得到一个均匀的带有模糊效果的副本. 不同种类的模糊算法有很大差异, 并且错综复杂, 这里我们仅仅讨论一个常用的Gaussian blur(高斯模糊).
通常, 模糊算法会根据一个像素周围的像素为其生成一个新的色值.考虑下面的网格图片:
上面的每一个网格单元代表了一个独立的像素, 每一个像素都有一个1~10之间的数字. 当模糊算法在计算中间像素对应的新值时, 会取其周围数字的平均值填入其中. 得到下面的结果:
你可以对原始图片的每一个像素都执行上述过程.
上述过程只是对某一个像素周围的每个方向取一个像素计算新的值. 你可以扩大模糊半径(上述案例的中间像素的外围像素个数)从而增加模糊程度. 下面是个例子:
注意事项: 通常, 更大的模糊半径意味着处理图片需要更多的资源. iOS通常会将处理图片的任务转交给GPU, 去保证主线程的通畅.
模糊效果设计策略
人们更倾向于把注意力集中在清晰的元素上, 而不是不清晰的. 不管你信还是不信, 这就是我们的眼睛工作的结果. 随着物体变近或远, 眼睛随之聚焦, 这就是适应(Focusing on an object as it moves closer or further away from the eye is known as accommodation), 是他帮助你观察周围事物的深度和距离.
APP的设计师们运用了这个事实, 将屏幕上那些不重要的元素变得模糊, 从而使人们的实现保留在清晰的元素上.下面是一个示例, Twitter客户端的截屏:
上面的图片中, 背后的用户界面几乎是不能辨别的, 这为用户提供了一个环境, 去识别他们处在哪个层级关系中.例如, 你可能会意识到, 一旦你选择了列出账号中的一个, 你就会返回到后面带有模糊效果的视图中.
注意: 避免在你的APP中滥用模糊效果.即使模糊能提供很好看的效果, 如果你使用不当或使用过于频繁, 它也会令人烦恼.
跟随设计标准去使用模糊可以直接吸引用户注意力, 那样你几乎不会失败.查看Apple开发者中心的iOS Human Interface Guidelines document文档中Designing for iOS部分可以获取更多信息.
开始动手
为了学习如何实现模糊效果, 你需要在GrimmAPP中添加一些.
这个APP向用户展示了很多童话故事. 当用户点击其中一个时, APP会在屏幕上展现整个故事.用户可以自定义展现的字体, 文本的对其方式, 或颜色主题(白天或夜晚).
你可以下载这个工程开始, 在Xcode中打开Grimm.xcodeproj. 点击Main.storyboard你会看到下面的视图:
你可以忽略最开始的controller, 它是APP的根导航控制器. 依次点击带有编号的控制器, 你将看到如下内容:
- 第一个控制器是
StoryListController, 它是数据库中所有故事的列表. - 点击列表中的一个故事, 将来到
StoryViewController, 它展示了点击故事的标题和具体内容. OptionsController是包含在StoryViewController控制器中的, 展示了支持的字体, 文本对其方式, 颜色等. 若想展示它, 只需点击详情页右上角省略号的按钮.
编译并运行, 你将看到下面的初始画面:
一旦你理解了该APP是如何工作的, 就直接进入下一部分. 向该APP添加模糊效果吧.
使用UIVisualEffectView添加模糊效果
UIKit提供了一整套视觉效果.UIBlurEffect(它是UIVisualEffect的子类), 是和你的兴趣相关的.UIBlurEffect提供了很漂亮的视觉效果, 就像你在navigation bars,Notification Center,Control Center中看到的那样. 你也可以将其用到你的APP中.
添加UIBlurEffect
在这个工程中, 你将使用模糊效果使OptionsController在故事的顶部显得更加突出.让我们投入其中吧!
打开OptionsController.swift, 添加下面的代码到viewDidLoad:方法的结尾处:
// 1
view.backgroundColor = .clear
// 2
let blurEffect = UIBlurEffect(style: .light)
// 3
let blurView = UIVisualEffectView(effect: blurEffect)
// 4
blurView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(blurView, at: 0)
依次解释下:
- 为了能够让
UIVisualEffectView视图内容模糊起来, 它的父视图必须是透明的. 为了做到这点, 你将self.view的背景改成了clear - 使用
UIBlurEffectStyle.light创建了一个UIBlurEffect. 这定义了模糊的风格. 其他支持的风格还有.extraLight,.dark,.extraDark,regular,prominent(实际上我并没有找到extraDark). - 使用上一步创建的
UIBlurEffect来创建UIVisualEffectView. 它是UIView的子类.它唯一的目的是描绘复杂模糊的外形和显示它. - 关闭了
blurView的auto-resizing而使用constraints, 稍后你将手动添加constraints到它上面. 添加它到视图栈的底端. 若你在顶端添加blurView, 这将使下面的所有元素变得模糊.
现在, 你要确定blurView被安放在合适的位置.添加下面的代码到viewDidLoad:方法的结尾处:
NSLayoutConstraint.activate([
blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
])
这些约束使blurView的frame和OptionsController的view是一样的.
编译并运行, 选择一个故事, 点击省略号的按钮, 滚动文本, 你会发现模糊效果在实时的更新.
现在, 你在你的APP中实现了一个动态的模糊效果, 它不仅实现简单, 而且看上去很漂亮.
使你的模糊效果更有活力
模糊效果很好, 但Apple使用UIVibrancyEffect将其带入了下一个等级, 使用它可以使内容色彩更生动.
如下图:
注意:
UIVibrancyEffect必须添加到UIVisualEffectView的contentView中(它已经被正确放置, 使用UIBlurEffect配置过的)!否则不会向任何模糊的效果上添加"生动效果".
打开OptionsController.swift, 添加下面的代码到viewDidLoad:方法的结尾处:
// 1
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
// 2
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
// 3
vibrancyView.contentView.addSubview(optionsView)
// 4
blurView.contentView.addSubview(vibrancyView)
依次解释下:
- 使用之前配置好的
blurEffect创建一个UIVibrancyEffect.UIVibrancyEffect是UIVisualEffect的另一个子类. - 创建一个
UIVisualEffectView用来包含UIVibrancyEffect效果. 这个步骤和之前创建模糊效果是一样的. 一旦你使用了Auto Layout, 确定将auto-resizing关闭. - 将
optionsView作为vibrancyView中contentView的子视图. 这将确保生动效果应用到其包含的每一个元素中. - 最后, 将vibrancyView添加到blurView的contentView中, 完成最终的效果.
接下来, 你要为vibrancyView设置自动布局的约束, 以便和blurView的尺寸一样, 以及确保optionsView在vibrancyView的中心位置.
添加下面的代码到viewDidLoad:方法的结尾处:
NSLayoutConstraint.activate([
vibrancyView.heightAnchor.constraint(equalTo: blurView.contentView.heightAnchor),
vibrancyView.widthAnchor.constraint(equalTo: blurView.contentView.widthAnchor),
vibrancyView.centerXAnchor.constraint(equalTo: blurView.contentView.centerXAnchor),
vibrancyView.centerYAnchor.constraint(equalTo: blurView.contentView.centerYAnchor)
])
NSLayoutConstraint.activate([
optionsView.centerXAnchor.constraint(equalTo: vibrancyView.contentView.centerXAnchor),
optionsView.centerYAnchor.constraint(equalTo: vibrancyView.contentView.centerYAnchor),
])
你还有一个事情需要注意, 看下viewDidLoad:的开始部分, 你以及将optionsView作为self.view的子视图了, 而一个视图只能有一个父视图.
在viewDidLoad:的开始部分注释掉下面的代码:
view.addSubview(optionsView)
NSLayoutConstraint.activate([
view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
])
编译并运行, 你将看到新的效果已经生效:
除非有较大差异的版本, 否则这个效果会各个元素难以辨认. 这发生了什么?
告诉你吧! 在blurView下一层的视图是偏亮的, 而又使用了UIBlurEffectStyle.light的效果. 这将适得其反, 就像上面的效果.
修改初始化blurEffect的代码如下:
let blurEffect = UIBlurEffect(style: .dark)
这个改变使背景和文字又来较大的差异.编译运行, 你将看到下面的效果:
更进一步
在使用模糊效果时, 还有最后一点需要注意: 如果用户将模糊效果禁用了, 将会发生什么?
在模拟器或你的设备中, 打开设置, 进入General\Accessibility\Increase Contrast, 打开Reduce Transparency.(真机中应该是 通用\辅助功能\增强对比度\降低透明度 开关).返回到这个APP中, 再次打开optionsView, 你将看到下面的结果:
可以看到它没有正常工作. 这种情况下, 你最好回到开始的地方.
幸运的是, 你可以使用UIAccessibilityIsReduceTransparencyEnabled()方法判断辅助功能是否打开.你可以像下面这样修改:
guard UIAccessibilityIsReduceTransparencyEnabled() == false else {
view.addSubview(optionsView)
NSLayoutConstraint.activate([
view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
])
return
}
OK, That's all!
多说一句, 你可以进入UIAccessibility类中, 看看可以检测哪些开关的状态的.
结语
整个过程中, 最大的感触是国内外的文风相差不是一丁半点啊. 国外的偏向故事风格有木有. 收获还是不少的, 感谢大家的陪伴, 让我们一起进步!
注
- 部分图片来源于网络,如有侵权,请告知。
- 如有错误,还请指出。共勉!
- 您的喜欢是最大的赞赏。