- 原本链接
- 本文为翻译文,如有错误,欢迎指正
ios11已经揭开神秘面纱,虽然整体画风依旧简单,但系统上的变化也是清晰可见的,其中之一就是ios标志性控件导航栏的设计发生了变化。
来看下ios11中新出现的Files

标题栏变大了,新的搜索框 --- 这都是ios11最醒目的变化。
来看一下横向的画面

Tab Bar 高度减少,btn位置也发生了变化。
本文将针对ios中一些醒目的UI变化最一下简短的说明。
ios 的核心UI Bar控件:导航栏、UIToolBar、TabBar、搜索框等,以及margin,inset等各种UI约束。
UIBarItem
首先来看一下TabBar,导航栏,toolBar等的父类UIBarItem。
像上面两个截图展示的一样,横屏时也可以用较小的icon。请看下面截图


在画面中间显示的是待选项目大的icon及title。
可以看出这并不是平时模式下常用的UI。
这是专门针对视力不好的人,在“文字放大查看”选项被选中时才出现的项目。
(使用方法:iPhone 设置app>通用>辅助功能>大号文字> 显示大号文字)
请按导航栏或是Tab bar时,将出现上图所述情况,放大显示现在已选中项目。
ios10及以前的系统,选择放大选项时,并不会同时方法导航栏或tab bar里的文字,因此对视力不好的人带来了一定的不便。
大家可以看到,ios11为覆盖此部分功能,引入的新的辅助性UI。
为设置UIBarItem,来看一下核心api。
// 标题
UIBarItem.title
// 图片
UIBarItem.image
// 横屏用图片
UIBarItem.landscapeImagePhone
// 视力不好的人专用的图片
UIBarItem.largeContentSizeImage
若通过StoryBoard设置,就不像上文一样用很多图片,也可以使用一个PDF文件,在这种情况下需要勾选Preserve Vector Data。

设置大的TitleBar
若想在导航栏中设置大的标题,只需要添加一行代码。
navigationBar.prefersLargeTitles = true
但如果只设置这一行代码,那与此导航栏想关联的所有viewController都会显示大标题。
一般来说只有第一或者第二个标题需要大号字体,以内容为主的画面不需要导航栏出现大的标题。
navigationItem.largeTitleDisplayMode
这是需要修改navigationItem的 largeTitleDisplayMode属性。
-
有.automatic, .always, .never 3个值, .automatic 是默认值
- .automatic 表示与之前画面相同
- .always表示总显示大号标题
- .never 表示不显示大标题,显示原字
-
navigationBar: UINaivgationBar 是 UINavigationController 里的property ,
-
navigationItem: 请记住UINavigationItem 是 UIViewController 的property
搜索栏
- 新的搜索框与之间相比简化许多,设计也是一目了然
navigationItem.searchController
navigationItem.hidesSearchBarWhenScrolling
- searchController: 只要设置UISearchController ,那搜索的UI就会自动设置出来。之前给搜索UI做约束比较麻烦,现在升级后的方式很简单 :)
UINavigationBar及 UIToolbar 都支持 Auto Layout
现在可以自定义UINavigationBar及UIToolbar 控件中的Auto Layout 属性.更准确的说,可以修改 Auto Layout 的大小属性; 使用intrinsicContentSize或是直接定义width, height 属性都可以。
Layout Margins

- UIView的 layoutMargins: UIEdgeInsets在设置相关view的自子控件时起向导作用,引导并尽量使子空间只设置在该margin内侧.
(layoutMargins 并不是为约束 UI而强制使用的语法)

layoutMarginsGuide是为了layoutMargins在 auto layout中使用的值.

在iOS 11中 ,新添加了directionalLayoutMargins, 官方推荐代替layoutMargins 使用。

layoutMargins作为 UIEdgeInsets,只有left和 right的值, directionalLayoutMargins作为 NSDirectionalEdgeInsets,也包含了 leading, trailing的值.
NSDirectionalEdgeInsets也是 iOS 11中新增加的类.
Directional 이란 개념은在 iOS UI 开发中Directional这个概念非常重要。
代替Left, Right,使用Leading, Trailing 的概念,对书写习惯为从右到左的国家来说非常重要。普通书写习惯为从左到右,因此UI的标准也是左边,但是对阿拉伯国家来说,习惯从右往左,因此UI约束也以右边为基准,与普通情况正好相反。


为directionalLayoutMargins的 trailing值赋值时,对一般情况会从右边留白,但针对以右边为基准的国家,对从左边留白。

layoutMargins, directionalLayoutMargins 无论变更哪一个,两个值都会同时改变。但要明确区本left, right, leading, trailing在概念上的差异。

iOS 11 之前的系统会提供 layoutMargins的默认值。是(8,8,8,8) 这种形式. 从此版本起将不再提供,默认值为0。

并且在 UIViewController中增加了新属性systemMinimumLayoutMargins .

- layoutMargins与 directionalLayoutMargins 都以systemMinimumLayoutMargins 为基准发生作用。
- 不要忘记, layoutMargins与 directionalLayoutMargins是UIView的属性, systemMinimumLayoutMargins是UIViewController的属性.

但也有可以忽视 systemMinimumLayoutMargins的方法。可以使用UIViewController.viewRespectsSystemMinimumLayoutMargins



忽略systemMinimumLayoutMargins,并将directionalLayoutMargins的值设为 .zero时,内容可以填充满整个屏幕
LayoutGuide and SafeArea

topLayoutGuide与 bottomLayoutGuide被废弃了.
在查看代替他们的属性前,先看一下以前的属性是什么作用。iOS 7中ios设计实在不怎么样,为强化内容,使用full screen,透明处理导航栏和toolBar.
关于iOS设计的相关细节,请参考 iOS Human Interface Guideline 文档。

一般来说内容较长时都需要滚动。要想知道导航栏或者工具栏实际哪些领域被覆盖的话,需要使用topLayoutGuide和 bottomLayoutGuide
edgesForExtendedLayout属性决定内容是否要覆盖底部Bar的部分。

现在不比使用 topLayoutGuide和 bottomLayoutGuide.
作为替代,使用Safe Area这一属性。
虽然topLayoutGuide与 bottomLayoutGuide是UIViewController的属性,但新的Safe Area是 UIView的属性。
UIView.safeAreaInsets: UIEdgeInsets
UIView.safeAreaLayoutGuide: UILayoutGuide
可以通过这两个参数判断领域。



除导航来和ToolBar之外,像上图中出现的图片bar部分的领域,可以通过自定义来解决, 通过设置UIViewController.addtionalSafeAreaInsets ,领域变更后可以调用两个方法来确定是否变更。
UIView.safeAreaInsetsDidChange()
UIViewController.viewSafeAreaInsetsDidChange()
UITableView
接下来是TableView,在ios11中tableview有一个重要的变化。
从现在起, UITableView 的Self-Sizing变为 Default.
换句话说,现在tableView是在Auto Layout 的基础上设置的。tableView 的cell及headView,footView等要通过 Auto Layout 来改变。
(当然,肯定可以继续按照以前的方式开发)
PS: UITableView以Auto Layout为基础的话,那就需要设置UITableView.estimatedRowHeight为 UITableViewAutomaticDimension.
iOS 11中,这是默认值,不需要单独设置;只是若按之间的方式开发,那需要做如下设置。
override func viewDidLoad() {
tableView.estimatedRowHeight = 0
tableView.estimatedSectionHeaderHeight = 0
tableView.estimatedSectionFooterHeight = 0
}
在来看一下其他tableView的 Separator inset .
首先,若在 iPad 上写一个简单的tableView.
import UIKit
class ViewController: UIViewController {
override func loadView() {
view = UITableView()
}
override func viewDidLoad() {
super.viewDidLoad()
let tableView = view as! UITableView
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dataSource = self
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Table view cell"
return cell
}
}

iPad中,若使tableView充满整个若面, separatorInset 将自适应readable content guide.
在此基础上若想重新设置separatorInset该怎么办呢?
iOS11与之间版本有所不同,需要添加如下代码.
// in viewDidLoad
tableView.separatorInset = UIEdgeInsets(top: 0, left: 50, bottom: 0, right: 0)


虽然是一样的代码,但会像上图显示不同的结果。iOS 10 中 separatorInsets 还是以 readable content guide 为基准设置 inset ,
iOS 11 中则是像开发者希望的那样,从cell的最边缘开始算 inset.
那iOS 11若想向以前一样设置为readable content guide 该怎么办呢?
// in viewDidload
tableView.separatorInsetReference = .fromAutomaticInsets
将新属性 separatorInsetReference的值设为 값을 automatic即可。
separatorInsetReference: UITableViewSeparatorInsetReference 有两个枚举值.
public enum UITableViewSeparatorInsetReference : Int {
// The value set to the separatorInset property is interpreted as an offset from the edges of the cell.
case fromCellEdges
// The value set to the separatorInset property is interpreted as an offset from the automatic separator insets.
case fromAutomaticInsets
}
此外:
- UITableViewCell, UITableViewHeaderFooterView 的contentView 总在 safe area里面,一定要使用 contentView
- tableView的header和footer以及分组内部的header和footer都使用 UITableViewHeaderFooterView

最后,说明一下,在ios11中已完全支持Swipe Actions。
这真是让很多程序员热泪盈眶呀、
左、有都可以加入很多手势,iPhone的邮件app可以通过Swipe action删除。
详细内容请看WWDC17
网友评论