返回 导航

Swift

hangge.com

Swift - 异步编程库PromiseKit使用详解4(KVO的扩展)

作者:hangge | 2018-12-10 08:10
    KVO(键值观察)是一种 Objective-C 的回调机制,全称为:key-value-observing。该机制简单来说就是在某个对象注册监听者后,当被监听的对象发生改变时,对象会发送一个通知给监听者,以便监听者执行回调操作。

    同样地,PromiseKit 也对 KVO 提供了相关的扩展,方便我们使用。

五、KVO 的扩展

1,准备工作

我们同样要安装 PromiseKit 库,以及相关的 PMKFoundation 扩展库,具体步骤参考我之前的文章:

2,监听基本类型的属性

(1)我们创建一个定时器,每隔 1 秒钟给变量 message 尾部添加一个感叹号(!)。同时对这个属性进行监听,当值改变时将最新值输出到控制台中。
注意:监听的属性需要有 dynamic 修饰符。
import UIKit
import PromiseKit
import PMKFoundation

class ViewController: UIViewController {
    
    @objc dynamic var message = "hangge.com"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //定时器(1秒执行一次)
        Timer.scheduledTimer(timeInterval: 1, target: self,
                                selector: #selector(ViewController.changeMessage),
                                userInfo: nil, repeats: true)
        
        //观察message参数变化
        observeMessage()
    }
    
    //计时器时间一到修改参数内容
    @objc func changeMessage(){
        //每次给字符串尾部添加一个感叹号
        self.message.append("!")
    }
    
    //观察message参数变化
    func observeMessage(){
        self.observe(.promise, keyPath: #keyPath(ViewController.message)).done { value in
            print(value ?? "")
            //继续观察
            self.observeMessage()
        }
    }
}

(2)运行结果如下:

3,监听视图尺寸变化

(1)我们对 view.frame 进行监听,当其改变时将最新值输出到控制台中。
import UIKit
import PromiseKit
import PMKFoundation

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //监听view.frame变化
        observeViewFrame()
    }
    
    //监听view.frame变化
    func observeViewFrame(){
        self.observe(.promise, keyPath: #keyPath(view.frame)).done { frame in
            print("--- 视图尺寸发生变化 ---")
            print(frame!)
            //继续观察
            self.observeViewFrame()
        }
    }
}

(2)程序启动后默认是竖屏状态,接着我们将其变成横屏显示。控制台输出内容如下:

4,渐变导航栏效果

(1)效果图如下,导航栏会随着 tableView 的滑动而发生不同的变化:
         

(2)我们可以通过 KVO 监听偏移量的变化来动态改变导航栏的背景透明度:
import UIKit
import PromiseKit
import PMKFoundation

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @objc var tableView:UITableView!

    //导航栏背景视图
    var barImageView:UIView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //导航栏背景色为橙色
        self.navigationController?.navigationBar.barTintColor = .orange
        
        //获取导航栏背景视图
        self.barImageView = self.navigationController?.navigationBar.subviews.first
    
        //创建表视图
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        self.tableView.delegate = self
        self.tableView.dataSource = self
        //创建一个重用的单元格
        self.tableView.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "SwiftCell")
        
        self.view.addSubview(self.tableView)
        
        //使用kvo来监听视图偏移量变化
        observeTableViewContentOffset()
    }
    
    //监听tableView.contentOffset变化
    func observeTableViewContentOffset(){
        self.observe(.promise, keyPath: #keyPath(tableView.contentOffset)).done { oldOffset in
            var delta = self.tableView.contentOffset.y / CGFloat(64) + 1
            delta = CGFloat.maximum(delta, 0)
            self.barImageView?.alpha = CGFloat.minimum(delta, 1)
            //继续观察
            self.observeTableViewContentOffset()
        }
    }
    
    //在本例中,只有一个分区
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    //返回表格行数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }
    
    //创建各单元显示内容(创建参数indexPath指定的单元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //为了提供表格显示性能,已创建完成的单元需重复使用
            let identify = "SwiftCell"
            //同一形式的单元格重复使用,在声明时已注册
            let cell = tableView.dequeueReusableCell(withIdentifier: identify,
                                                     for: indexPath)
            cell.accessoryType = .disclosureIndicator
            cell.textLabel?.text = "这个是条目\(indexPath.row)"
            return cell
    }
}

评论

全部评论(0)

回到顶部