如何在UITableViewController之上添加UIView?数据加载场景需求
在UITableViewController上添加加载状态视图的实现方案
嘿,这个需求其实挺常见的,我来给你几个靠谱的实现思路,亲测好用~
方法一:全屏覆盖式加载视图(推荐用于需要阻止用户操作的场景)
这种方法会在整个tableView上方叠一层加载视图,直到数据加载完成,适合需要防止用户在加载时交互的情况。
步骤:
- 先定义一个加载视图的属性,在
viewDidLoad中初始化并添加到控制器的view上(因为UITableViewController的view就是tableView,所以添加后层级更高,会覆盖在tableView之上) - 发起网络请求前显示该视图,加载完成后隐藏并刷新tableView
代码示例(Swift):
class ContactsTableViewController: UITableViewController { private var loadingOverlayView: UIView! private var contacts: [Contact] = [] // 你的联系人模型数组 override func viewDidLoad() { super.viewDidLoad() setupLoadingOverlay() startFetchingContacts() } // 初始化全屏加载视图 private func setupLoadingOverlay() { loadingOverlayView = UIView(frame: view.bounds) // 设置半透明背景,让用户能看到下方的tableView但无法操作 loadingOverlayView.backgroundColor = UIColor.systemBackground.withAlphaComponent(0.8) loadingOverlayView.isUserInteractionEnabled = true // 拦截用户点击 // 添加活动指示器(换成UIImageView就是图片加载视图) let activityIndicator = UIActivityIndicatorView(style: .large) activityIndicator.center = loadingOverlayView.center activityIndicator.color = .systemBlue activityIndicator.startAnimating() loadingOverlayView.addSubview(activityIndicator) // 初始状态隐藏 loadingOverlayView.isHidden = true view.addSubview(loadingOverlayView) } private func startFetchingContacts() { // 显示加载视图 loadingOverlayView.isHidden = false // 模拟网络请求(替换成你的实际API请求) URLSession.shared.dataTask(with: URL(string: "https://your-contacts-api.com")!) { [weak self] data, response, error in guard let self = self else { return } // 这里处理数据解析,把结果赋值给contacts数组 if let data = data { // 假设用JSONDecoder解析 do { self.contacts = try JSONDecoder().decode([Contact].self, from: data) } catch { print("解析失败:\(error)") } } // 回到主线程更新UI DispatchQueue.main.async { self.loadingOverlayView.isHidden = true self.tableView.reloadData() } }.resume() } }
方法二:TableHeaderView加载视图(适合非全屏的加载提示)
如果你希望加载视图只显示在tableView的顶部,而不是覆盖整个屏幕,可以用tableHeaderView来实现。
步骤:
- 初始化一个加载视图作为tableView的header,初始时设置高度为0(隐藏状态)
- 发起请求前设置header的高度为你想要的尺寸,显示加载视图
- 加载完成后把header高度设回0,隐藏并刷新tableView
代码示例(Swift):
class ContactsTableViewController: UITableViewController { private var loadingHeaderView: UIView! private var contacts: [Contact] = [] override func viewDidLoad() { super.viewDidLoad() setupLoadingHeader() startFetchingContacts() } private func setupLoadingHeader() { let headerHeight: CGFloat = 200 loadingHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: headerHeight)) loadingHeaderView.backgroundColor = UIColor.systemGray5 // 添加活动指示器或图片 let loadingImage = UIImageView(image: UIImage(named: "loading-placeholder")) loadingImage.contentMode = .scaleAspectFit loadingImage.center = loadingHeaderView.center loadingHeaderView.addSubview(loadingImage) // 初始时设置header高度为0,隐藏 tableView.tableHeaderView = loadingHeaderView tableView.tableHeaderView?.frame.size.height = 0 } private func startFetchingContacts() { // 显示加载header tableView.tableHeaderView?.frame.size.height = 200 URLSession.shared.dataTask(with: URL(string: "https://your-contacts-api.com")!) { [weak self] data, response, error in guard let self = self else { return } // 解析数据... if let data = data { do { self.contacts = try JSONDecoder().decode([Contact].self, from: data) } catch { print("解析错误:\(error)") } } DispatchQueue.main.async { // 隐藏header self.tableView.tableHeaderView?.frame.size.height = 0 self.tableView.reloadData() } }.resume() } }
额外注意点
- 必须在主线程更新UI:网络请求是在后台线程执行的,所以更新加载视图的隐藏状态和刷新tableView一定要放到
DispatchQueue.main.async里,否则会崩溃或者不生效。 - 自定义加载视图:如果需要用图片代替活动指示器,只需要把代码中的
UIActivityIndicatorView换成UIImageView,设置好图片和布局即可。 - 用户交互控制:如果用全屏覆盖视图,记得设置
isUserInteractionEnabled = true,这样用户在加载时无法点击tableView的单元格,避免无效操作。
内容的提问来源于stack exchange,提问作者RasiqKhan
相关产品推荐
相关产品推荐

