实现思路
1.用ta b le view指定了刷新的内容区域,当下拉刷新时,若超出了table的内容的空白区域,系统会自动弹回内容的原位置。因此可以将刷新的vie w放在scrollview的上面
2.随着用户的滚动更新refresh vie w中的内容,根据用户向下拉动的远近来改变view背景色,视差滚动
3.用户松开结束滚动时,应该进行一次判断,判断用户是否要刷新页面。因为刷新将伴随着网络下载。只有当滚动到足够距离的时候,才认为是下拉刷新。
此时才回锁定到刷新的页面,并让其保持可见的状态。做动画的处理
此时心中会有一些问题
如何追踪用户的滚动进度?
*refreshview的可见区域的高度= content offset.y - contentInset.top.y
上代码
1.准备工作要注意的地方,我用图片进行展示
2.创建刷新的视图:RefreshView.swift
`private unowned var scrollView : UIScrollView //unowened相当于o c的weak
init(frame : CGRect, scrollView : UIScrollView) {
self.scrollView = scrollView;
super.init(frame: frame)
backgroundColor = UIColor.green
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
`
让刷新视图相应用户下拉的操作
当用户下拉table的时候会响应系统的一个通知,因此会响应scrollviewdidscroll方法
下拉刷新的渐变效果核心代码如下:
//在refreshviewcontroller中
override func scrollViewDidScroll(_ scrollView: UIScrollView) { //把通知传递给refreshview,让他进行相应的变化 refreshView.scrollViewDidScroll(scrollView: scrollView) }
//在refresh view 中
` func updateBackgroundColor() {
backgroundColor = UIColor(white: 0.7*progress + 0.2, alpha: 1.0)
}
func scrollViewDidScroll(scrollView: UIScrollView) {
//刷新视图可见的区域
let refreshHeight = max(0, -scrollView.contentOffset.y - scrollView.contentInset.top)
//场景的高度
progress = min(1, refreshHeight/kSceneHeight)
//根据进度来改变背景色
updateBackgroundColor()
}`
视差滚动,即界面中的所有控件的动画,以不同的速度进行移动时,产生的立体的效果
确定一个动画需要知道控件的起始位置,结束位置,路径
它们之间的关系是 起始位置的y值 = 结束位置的y值 + 移动速率*场景的高度
创建一个工具类RefreshIterm.swift来处理动画的路径
`private var centerStart: CGPoint
private var centerEnd: CGPoint
unowned var view: UIView
//起始位置
init(view: UIView, centerEnd: CGPoint, parallaxRatio: CGFloat, sceneHeight: CGFloat) {
self.view = view
self.centerEnd = centerEnd
centerStart = CGPoint(x: centerEnd.x, y: centerEnd.y + (parallaxRatio * sceneHeight))
self.view.center = centerStart
}
//跟据下拉的进度确定控件的位置
func updateViewPositionForPercentage(percentage: CGFloat) {
view.center = CGPoint(
x: centerStart.x + (centerEnd.x - centerStart.x) * percentage,
y: centerStart.y + (centerEnd.y - centerStart.y) * percentage)
}`
在refresh view中加载做动画的控件
`func setupRefreshItems() {
let groundImageView = UIImageView(image: UIImage(named: "ground"))
let buildingsImageView = UIImageView(image: UIImage(named: "buildings"))
refreshItems = [
RefreshIterm(view: buildingsImageView, centerEnd: CGPoint(x: bounds.midX,
y: bounds.height - groundImageView.bounds.height - buildingsImageView.bounds.height / 2), parallaxRatio: 1.5, sceneHeight: kSceneHeight),
RefreshIterm (view: groundImageView,
centerEnd: CGPoint(x: bounds.midX,
y: bounds.height - groundImageView.bounds.height/2),
parallaxRatio: 0.5, sceneHeight: kSceneHeight),
]
for refreshItem in refreshItems {
addSubview(refreshItem.view)
}
}`
控件滚动的时候,改变控件的位置
func updateRefreshItemPositions() { for refreshItem in refreshItems { refreshItem.updateViewPositionForPercentage(percentage: progress) } }
自定义动画的刷新和锁定,通过判断用户是不是拉的足够远来决定是否要执行刷新的操作
首先声明一个de le ga te属性,在声明一个是否刷新的状态变量isrefreshing
开始刷新,调用UI view的animateWithDuration方法,将scrollview的contentins e t加上上场景的高度
出发刷新,首先不是正在刷新,下拉的进度最大时 ,触发刷新。
触发代理使控制器进行刷新操作
核心代码:
` func beginRefreshing() {
isRefreshing = true
UIView.animate(withDuration: 0.4, delay: 0, options: .curveEaseInOut, animations: { () -> Void in
self.scrollView.contentInset.top += kSceneHeight
}) { (_) -> Void in
}
}`
func endRefreshing() { UIView.animate(withDuration: 0.4, delay: 0, options: .curveEaseInOut, animations: { () -> Void in self.scrollView.contentInset.top -= kSceneHeight }) { (_) -> Void in self.isRefreshing = false } }
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer
运行效果为:
demo地址下载