事件详情: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()// 刷新数据.最后停止动画
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?