动态形态的应用

动态形态是 iOS 7 开始引入的,有了这个功能,允许使用者自定义 App 文字的大小来满足他们的需要。不过,只有采用了动态形态的 App 的文字才能跟着设置变化。

相关知识可以参考 Apple 的人机界面指南 ( Apple’s Human Interface Guidelines)

对于一般的标签,只需要用系统内置的 「Text Style」来代替固定的字体设置即可。

但是在设置为动态字体后,由于 Label 的默认行数是1行,有些 Label 的内容在放大后会显示不下。就会出现被省略号隐藏并截断的情况。

这时候需要对 Label 的 numberOfLines 进行设置。不设置的话,默认为 1。即为规定为 1 行文本。设置为 0 则为无限制。

可以在 TableViewCell 中的变量定义中插入如下代码

    @IBOutlet var locationLabel: UILabel!{
        didSet {
            locationLabel.numberOfLines = 0
            
        }
    }

如果 Label 是在 Cell 里,那么就得对 Cell 开启动态高度。

经过这样的设置后,App 就可以动态适应不同的字体大小了。

导览列透明效果的实现

//需要添加进 ViewController 的 viewDidLoad 中
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()

要让导览列变透明,只需要设定背景图片与阴影图片为一张空白图片,也就是 UIImage()

效果如上

一个 cell 的套用模板的实现

//以下是 ViewController 的代码

import UIKit

class RestaurantDetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableView: UITableView!
    @IBOutlet var headerView: RestaurantDetailHeaderView!
    
    var restaurant = Restaurant()

    // MARK: - View controller life cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.largeTitleDisplayMode = .never
        
        // Configure header view
        headerView.nameLabel.text = restaurant.name
        headerView.typeLabel.text = restaurant.type
        headerView.headerImageView.image = UIImage(named: restaurant.image)
        headerView.heartImageView.isHidden = (restaurant.isVisited) ? false : true
        
        // Configure the table view
        tableView.delegate = self
        tableView.dataSource = self
        //程序和 cell 视图中的数据关联
        //与 Storyboard 来关联,二选一
        tableView.separatorStyle = .none
        //设置样式为 .none 以移除表格的分界线
    }
    
    // MARK: - Table view data source
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
         //表示表格视图只有一个区块
         //缺省为 1,不写不影响运行
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }
    //定义 cell 有三个小节
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        switch indexPath.row {
        //用 switch 控制三个小节的渲染,并用 indexPath.row 进行判断
            
        case 0:
            let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: RestaurantDetailIconTextCell.self), for: indexPath) as! RestaurantDetailIconTextCell
            //调用 RestaurantDetailIconTextCell (第一个小节模板),带描述和图标。用 as!将 cell 向下转型为 RestaurantDetailIconTextCell,以方便调用其方法
            cell.iconImageView.image = UIImage(systemName: "phone")?.withTintColor(.black, renderingMode: .alwaysOriginal)
            //调用系统内置“电话”图标,并通过 withTintColor 赋予黑色。内置图标默认蓝色
            //renderingMode(渲染模式) 设置为 alwaysOriginal (始终绘制原始图像,而不将其视为模板)
            cell.shortTextLabel.text = restaurant.phone
            cell.selectionStyle = .none
            
            return cell
            //返回 cell 数据
            
        case 1:
            let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: RestaurantDetailIconTextCell.self), for: indexPath) as! RestaurantDetailIconTextCell
            //调用 RestaurantDetailIconTextCell (第一个小节模板),带描述和图标。用 as!将 cell 向下转型为 RestaurantDetailIconTextCell,以方便调用其方法
            cell.iconImageView.image = UIImage(systemName: "map")?.withTintColor(.black, renderingMode: .alwaysOriginal)
            //调用系统内置“地图”图标,并通过 withTintColor 赋予黑色。内置图标默认蓝色
            //renderingMode(渲染模式) 设置为 alwaysOriginal (始终绘制原始图像,而不将其视为模板)
            cell.shortTextLabel.text = restaurant.location
            cell.selectionStyle = .none
            
            return cell
            //返回 cell 数据

        case 2:
            let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: RestaurantDetailTextCell.self), for: indexPath) as! RestaurantDetailTextCell
            //调用 RestaurantDetailTextCell (第二个小节模板),只有描述。用 as!将 cell 向下转型为 RestaurantDetailTextCell,以方便调用其方法
            cell.descriptionLabel.text = restaurant.description
            cell.selectionStyle = .none
            
            return cell
            //返回 cell 数据
            
        default:
            fatalError("Failed to instantiate the table view cell for detail view controller")
        //在 case 0、1、2 都无法匹配的时候进行报错
        
        }
    }
}
效果图