前几天做了一个自定义下拉刷新的控件,http://www.jianshu.com/p/db2a46264522
现在想做一个在自定义上拉加载更多的控件,上拉加载的控件要比下拉刷新的简单的多,因为加载控件不应该有过多的动画,因为用户需要流畅的体验感,你懂的。所以状态就少了很多
首先依然是将我们的加载控件动态绑定到SCrollView中
private var pullUpLoadMoreView: QPullUpLoadMoreView? {
get {
return objc_getAssociatedObject(self, &Q_associatedKeys.pullUpLoadMoreView ) as? QPullUpLoadMoreView
}
set {
objc_setAssociatedObject(self, &Q_associatedKeys.pullUpLoadMoreView, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
控件的状态
public
enum pullUpLoadMoreState: Int {
case Default
case Dragging
case Trigger
case Failure
}
依然需要监听SCROLLView的状态,但是在这里只需要监听2个就够了
var observing: Bool = false {
didSet {
guard let scrollView = self.scrollView else { return }
if observing {
scrollView.safe_addObserver(self, forKeyPath: QTableViewRefreshConfig.KeyPaths.ContentOffset)
scrollView.safe_addObserver(self, forKeyPath: QTableViewRefreshConfig.KeyPaths.contentSize)
} else {
scrollView.safe_removeObserver(self, forKeyPath: QTableViewRefreshConfig.KeyPaths.ContentOffset)
scrollView.safe_removeObserver(self, forKeyPath: QTableViewRefreshConfig.KeyPaths.contentSize)
}
}
}
加载控件比下拉刷新控件更加方便的是,上拉加载的ContentInsetBottom的值可以是固定的,你可以想象一下,为什么可以是固定的,因为为了流畅度,当scrollViewOffsetY达到最底端的时候,我们控件就应该是触发态了,
override func didMoveToSuperview() {
super.didMoveToSuperview()
var contentInset = self.scrollView!.contentInset
contentInset.bottom = QTableViewRefreshConfig.LoadingMoreOffset
self.scrollView!.contentInset = contentInset
}
在做一个提示的label
init(){
super.init(frame: CGRectZero)
self.labelMsg.frame = CGRectMake(0, 0, 0, 0)
self.labelMsg.text = "loading ... "
self.labelMsg.font = UIFont(name: "ljq", size: 10.0)
self.labelMsg.textAlignment = NSTextAlignment.Center
self.addSubview(self.labelMsg)
}
监听
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == QTableViewRefreshConfig.KeyPaths.ContentOffset {
if let scrollView = self.scrollView where scrollView.contentOffset.y + scrollView.frame.size.height > scrollView.contentSize.height {
if scrollView.contentOffset.y != 0 {
if self.state == .Default{
self.state = .Trigger
self.labelMsg.text = "loading ... "
}else if state == .Trigger{
}
}
}
}else if keyPath == QTableViewRefreshConfig.KeyPaths.contentSize{
if let scrollView = self.scrollView where scrollView.contentSize.height != 0 {
self.frame = CGRectMake(0, self.scrollView!.contentSize.height, self.scrollView!.contentSize.width, QTableViewRefreshConfig.LoadingMoreOffset)
self.labelMsg.frame = CGRectMake(0, QTableViewRefreshConfig.LoadingMoreOffset/4, self.scrollView!.contentSize.width, QTableViewRefreshConfig.LoadingMoreOffset/2)
self.state = .Default
}
}
}
整个流程就是当滑动到底部的时候 state就变成Trigger, 然后开始加载更多,当加载完毕的时候COntentSize会重新计算,我们在监听COntentSize变化来调整我们LoadingMoreView的位置,使它一直保持在scrollView的底部。
当然为了效果好一点,我们需要一些小小的调整,比如在调用insertRowsAtIndexPaths方法之前,将LoadingMoreView隐藏掉,不然可能会出现重影的效果。
var state:pullUpLoadMoreState = .Default{
didSet{
switch state {
case .Default: self.hidden = false;
case .Dragging: break;
case .Trigger: self.actionHandler!()
case .Failure: self.labelMsg.text = "load fail , please up again" ; self.state = .Default
}
}
}
在控制器里面调用
self.tableView!.Q_addPullUpLoadMoreWithActionHandler{
[unowned self] () -> Void in
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
self.requreMoreData() //数据获取
// self.tableView!.Q_failLoadMore()
self.tableView!.Q_completeLoadMore()
var cells:[NSIndexPath] = [NSIndexPath]()
for index in 0...9 {
let cell:NSIndexPath = NSIndexPath(forRow: index+self.cellNum, inSection: 0)
cells.append(cell)
}
self.cellNum += 10
self.tableView!.insertRowsAtIndexPaths(cells, withRowAnimation: UITableViewRowAnimation.Automatic)
})
}
当然如果向在View里面做点动画也是很轻易的事情。附上效果图