Swift - 导航栏滑动透明渐变效果的实现(透明度随视图滚动而改变)
作者:hangge | 2018-05-22 08:10
导航栏透明渐变效果在许多 App 中也时常会见到。比如下图,导航栏会随着 tableView 的滑动而发生不同的变化:
- 默认情况下,导航栏背景是完全透明的。
- 当 tableView 向上滑动时,导航栏背景逐渐显示出来。
- 当 tableView 下载滑动时,导航栏背景又逐渐消失。

该效果的原理就是根据滚动视图的偏移量来设置导航栏的背景透明度,而监听偏移量的变化有如下两种方式。
方法一:通过 scrollViewDidScroll 方法监听滚动事件
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView?
//导航栏背景视图
var barImageView:UIView?
override func loadView() {
super.loadView()
}
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!)
}
//在本例中,只有一个分区
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//返回表格行数(也就是返回控件数)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
//创建各单元显示内容(创建参数indexPath指定的单元)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
//为了提供表格显示性能,已创建完成的单元需重复使用
let identify:String = "SwiftCell"
//同一形式的单元格重复使用,在声明时已注册
let cell = tableView.dequeueReusableCell(withIdentifier: identify,
for: indexPath)
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text = "这个是条目\(indexPath.row)"
return cell
}
//视图滚动时触发
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var delta = scrollView.contentOffset.y / CGFloat(64) + 1
delta = CGFloat.maximum(delta, 0)
self.barImageView?.alpha = CGFloat.minimum(delta, 1)
}
}
方法二:使用 KVO 监听滚动位置变化
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView?
//导航栏背景视图
var barImageView:UIView?
//KVO实例
var observation:NSKeyValueObservation?
override func loadView() {
super.loadView()
}
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!)
}
//在本例中,只有一个分区
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//返回表格行数(也就是返回控件数)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
//创建各单元显示内容(创建参数indexPath指定的单元)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
//为了提供表格显示性能,已创建完成的单元需重复使用
let identify:String = "SwiftCell"
//同一形式的单元格重复使用,在声明时已注册
let cell = tableView.dequeueReusableCell(withIdentifier: identify,
for: indexPath)
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text = "这个是条目\(indexPath.row)"
return cell
}
//视图显示时触发
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//使用kvo来监听视图偏移量变化
observation = self.tableView!.observe(\.contentOffset, options: [.new, .old]) {
[unowned self] tableView, changed in
//根据偏移量修改导航栏透明度
var delta = changed.newValue!.y / CGFloat(64) + 1
delta = CGFloat.maximum(delta, 0)
self.barImageView?.alpha = CGFloat.minimum(delta, 1)
}
}
//视图消失时触发
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//移除kvo监听
observation?.invalidate()
}
}
全部评论(1)
66行注释有误
//根据便宜了修改导航栏透明度
应该是偏移量
站长回复:谢谢你的提醒,代码现已修改。