事件详情:tableView上拉后不断刷新,基本上无法停止.

出现该事件的场景:在tableView中添加了多个自定义的Cell,当cell的总高度超出屏幕时即出现事件.下拉刷新无法回收并持续刷新.

导至我持续刷新的类是  MJRefreshAutoNormalFooter 我将其更换成 MJRefreshBackNormalFooter 后就没有出现类似问题了.

另外如果在停止刷新时表格会出现跳一下(抖一下)等情况时.使用

tableView.mj_header.endRefreshing {[weak self] in self.tableView.reloadData() } 在加载动画结束回调中再做数据刷新就不会有这个问题了.

主要解决思路就是将"刷新表格数据"事件和"结束mj刷新动画"事件分开执行. 根据需求你也可以先刷新表格数据,再结束mj刷新动画.比如:

   UIView.animate(withDuration: 0, animations: {

            self.tableView.reloadData()// 先刷新表格数据

        }, completion: { _ in

            self.tableView.mj_footer?.endRefreshing()// 最后结束mj刷新动画.

        })

其它碰到的问题

刷新完后表格仍然向上跳一节.但不会抖

1.可能是 tableView!.estimatedRowHeight 值设置过小.我试着加大了该值.表格就不跳了.

2.约束错有误.详细查看右下角的输出信息.如果有出现约束问题.解决就好了.

 

追加:因转用swift贴出对应swift中的个人封装.仅供参考.

 

**********************************分隔****************************************

 

import Foundation

import UIKit

import MJRefresh

 

extension UIScrollView {

    

    //MARK:---- global ----

    

    /// 默认配置

    ///

    /// - Parameter header: mj_header

    private class func xh_MJRefreshHeaderSetup(header:MJRefreshHeader) {

        header.isAutomaticallyChangeAlpha = true// 设置自动切换透明度(在导航栏下面自动隐藏)

    }

    

    /// footer默认配置

    ///

    /// - Parameter footer: mj_footer?

    private class func xh_MJRefreshFooterSetup(footer:MJRefreshFooter) {

        footer.isAutomaticallyChangeAlpha = true// 设置自动切换透明度(在导航栏下面自动隐藏)

    }

    

    //MARK:---- header ----

    

    /// mjheader刷新

    ///

    /// - Parameter completionHandle: 回调(配置刷新需要做的事)当header刷新时调用

    /// - Returns: 返回MJRefreshNormalHeader,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJRefreshHeader(completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshNormalHeader {

        let header = MJRefreshNormalHeader.init(refreshingBlock: completionHandle)

        mj_header = header

        UITableView.xh_MJRefreshHeaderSetup(header: header)

        return header

    }

    

    /// mjheader刷新

    ///

    /// - Parameters:

    ///   - IdleTitle: 空闲状态标题

    ///   - WillRefreshTitle: 即将刷新(拖动时)标题

    ///   - RefreshingTitle: 刷新中标题

    ///   - completionHandle: 回调(配置刷新需要做的事)当header刷新时调用

    /// - Returns: 返回MJRefreshNormalHeader,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJRefreshHeader(IdleTitle:String,pullingTitle:String,WillRefreshTitle:String,RefreshingTitle:String,completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshNormalHeader {

        let header = MJRefreshNormalHeader.init(refreshingBlock: completionHandle)

        self.mj_header = header

        UITableView.xh_MJRefreshHeaderSetup(header: header)

        header.setTitle(IdleTitle, for: .idle)

        header.setTitle(pullingTitle, for: .pulling)

        header.setTitle(WillRefreshTitle, for: .willRefresh)

        header.setTitle(RefreshingTitle, for: .refreshing)

        return header

    }

    

    /// mjheaderGIF刷新

    ///

    /// - Parameters:

    ///   - idle: 空闲状态

    ///   - pulling: 下拉中

    ///   - willRefresh: 即将刷新

    ///   - refreshing: 刷新中

    ///   - noMoreData: 没有更多数据

    ///   - completionHandle: 回调(配置刷新需要做的事)当header刷新时调用

    /// - Returns: mjheaderGIF刷新,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJGifHeader(idle:[UIImage]?,

                        pulling:[UIImage]?,

                        willRefresh:[UIImage]?,

                        refreshing:[UIImage]?,

                        noMoreData:[UIImage]?,

                        completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshGifHeader {

        let header = MJRefreshGifHeader(refreshingBlock: completionHandle)

        mj_header = header

        UITableView.xh_MJRefreshHeaderSetup(header: header)

        header.setImages(idle ?? [UIImage](), for: .idle)

        header.setImages(pulling ?? [UIImage](), for: .pulling)

        header.setImages(willRefresh ?? [UIImage](), for: .willRefresh)

        header.setImages(refreshing ?? [UIImage](), for: .refreshing)

        header.setImages(noMoreData ?? [UIImage](), for: .noMoreData)

        return header

    }

    

 

    

    //MARK:---- footer ----

    

    /// mjfooter刷新

    ///

    /// - Parameter completionHandle: 回调(配置刷新需要做的事)当footer刷新时调用

    /// - Returns: 返回MJRefreshBackNormalFooter,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJRefreshFooter(completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshBackNormalFooter {

        let footer = MJRefreshBackNormalFooter.init(refreshingBlock: completionHandle)

        self.mj_footer = footer

        UITableView.xh_MJRefreshFooterSetup(footer: footer)

        return footer

    }

    

    /// mjfooter刷新

    ///

    /// - Parameters:

    ///   - IdleTitle: 空闲状态标题

    ///   - WillRefreshTitle: 即将刷新(拖动时)标题

    ///   - RefreshingTitle: 刷新中标题

    ///   - completionHandle: 回调(配置刷新需要做的事)当footer刷新时调用

    /// - Returns: 返回MJRefreshBackNormalFooter,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJRefreshFooter(IdleTitle:String,WillRefreshTitle:String,RefreshingTitle:String,completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshBackNormalFooter {

        // 使用 MJRefreshAutoNormalFooter 中的 triggerAutomaticallyRefreshPercent 可以控制刷新高度

        let footer = MJRefreshBackNormalFooter.init(refreshingBlock: completionHandle)

        self.mj_footer? = footer

        UITableView.xh_MJRefreshFooterSetup(footer: footer)

        footer.setTitle(IdleTitle, for: .idle)

        footer.setTitle(WillRefreshTitle, for: .willRefresh)

        footer.setTitle(RefreshingTitle, for: .refreshing)

        return footer

    }

    

    /// mjfooterGIF刷新

    ///

    /// - Parameters:

    ///   - idle: 空闲状态

    ///   - pulling: 下拉中

    ///   - willRefresh: 即将刷新

    ///   - refreshing: 刷新中

    ///   - noMoreData: 没有更多数据

    ///   - completionHandle: 回调(配置刷新需要做的事)当footer刷新时调用

    /// - Returns: mjfooterGIF刷新,如需要特殊配置时可接收使用.

    @discardableResult func xh_MJGifFooter(idle:[UIImage]?,

                                           pulling:[UIImage]?,

                                           willRefresh:[UIImage]?,

                                           refreshing:[UIImage]?,

                                           noMoreData:[UIImage]?,

                                           completionHandle:@escaping MJRefreshComponentAction) -> MJRefreshBackGifFooter {

        let footer = MJRefreshBackGifFooter(refreshingBlock: completionHandle)

        mj_footer? = footer

        

        UITableView.xh_MJRefreshFooterSetup(footer: footer)

        footer.setImages(idle ?? [UIImage](), for: .idle)

        footer.setImages(pulling ?? [UIImage](), for: .pulling)

        footer.setImages(willRefresh ?? [UIImage](), for: .willRefresh)

        footer.setImages(refreshing ?? [UIImage](), for: .refreshing)

        footer.setImages(noMoreData ?? [UIImage](), for: .noMoreData)

        return footer

    }

    

    //MARK:---- other ----

 

    /// 停止MJ刷新(header 和 footer都停止)

    ///

    /// - Parameter completion: 完成回调

    func xh_endMJRefresh(completion: (() -> Void)? = nil) {

        let isHeaderRefreshing = mj_header?.isRefreshing == true

        let isFooterRefreshing = mj_footer?.isRefreshing == true

        if isHeaderRefreshing { mj_header?.endRefreshing { completion?() } }

        if isFooterRefreshing { mj_footer?.endRefreshing { completion?() } }

        if !isHeaderRefreshing && !isFooterRefreshing { completion?() }

    }

    

    /// 开始MJHeader刷新

    func xh_beginMJHeaderRefresh() {

        mj_header?.beginRefreshing()

    }

    

    /// 开始MJFooter刷新

    func xh_BeginMJFooterRefresh() {

        mj_footer?.beginRefreshing()

    }

    

    /// 停止MJFooter刷新,并设置为没有更多数据

    func xh_endMJFooterRefreshWithNoMoreData() {

        mj_header?.endRefreshing()

        mj_footer?.endRefreshingWithNoMoreData()

    }

    

    /// 配置下拉刷新高度

    ///

    /// - Parameter h: 刷新高度

    func xh_MJHeader(h:CGFloat) {

        mj_header?.mj_h = h

    }

    

    /// 配置上拉刷新高度

    ///

    /// - Parameter h: 刷新高度

    func xh_MJFooter(h:CGFloat) {

        mj_footer?.mj_h = h

    }

    

//    func xh_MJAutoRefresh(h:CGFloat) {// MJRefreshAutoFooter 才有此功能

//        self.mj_footer?.triggerAutomaticallyRefreshPercent = h

//    }

    

    /// 设置头部刷新视图的标题颜色

     /// - Parameter color: 标题颜色

     func xh_setMJHeaderTitle(_ color: UIColor) {

         if let header = mj_header as? MJRefreshNormalHeader {

             header.stateLabel?.textColor = color

         }

     }

     

     /// 设置头部刷新视图的子标题颜色

     /// - Parameter color: 子标题颜色

     func xh_setMJHeaderSubTitle(_ color: UIColor) {

         if let header = mj_header as? MJRefreshNormalHeader {

             header.lastUpdatedTimeLabel?.textColor = color

         }

     }

     

     

     /// 设置头部刷新子标题是否隐藏

     /// - Parameter isHidden: 是否隐藏

     func xh_hiddenMJHeaderSubTitle(_ isHidden:Bool = true) {

         if let header = mj_header as? MJRefreshNormalHeader {

             header.lastUpdatedTimeLabel?.isHidden = isHidden

         }

     }

    

    /// 清除没有更多数据状态.让底部视图可重新刷新.

    func xh_reSetNoMoreData() {

        mj_footer?.resetNoMoreData()

    }

    

}

 

extension UITableView {

    

    /// 刷新表格数据 后 停止刷新(header 和 footer都停止)

    /// - Parameter isNoMoreData: 是否将footer显示为没有更多数据

    func xh_reloadDataAndEndMJRefresh(_ isNoMoreData:Bool = false,callBack:XH_callBack? = nil) {

        self.isUserInteractionEnabled = false

        DispatchQueue.main.async {

            self.xh_reloadData {// 刷新数据后的回调

                if self.mj_header?.isRefreshing == true {

                    self.mj_header?.endRefreshing()

                }

                if self.mj_footer?.isRefreshing == true {

                    if isNoMoreData {

                        self.mj_footer?.endRefreshingWithNoMoreData()

                    } else {

                        self.mj_footer?.endRefreshing()

                    }

                }

                callBack?()

                self.isUserInteractionEnabled = true

            }

        }

    }

    

}

 

 

**********************************分隔****************************************

 

使用例子:

    

      tableView.xh_MJRefreshHeader {[weak self] in// 配置mjHeader .footer配置略

            self?.dosomething()

        }

 

结束刷新:

    //在刷新前要做好数据处理.刷新功能中已经写了让表格数据刷新

    self.infoList += list// 先把数据处理好.

    tableView.xh_reloadDataAndEndMJRefresh()// 刷新数据.最后停止动画