iOS 自动翻滚广告条(榜单条)实现方案

引言

在直播场景中,榜单信息、活动公告或者广告推广通常需要以醒目的方式展示,但由于屏幕空间有限,一次只能显示一条内容。为了让用户能够持续关注这些信息,我们可以实现一个自动翻滚的广告条(或榜单条),让内容定期滚动更新,类似于上下轮播的效果。

本篇博客将介绍如何使用 UITableView + Timer 来实现这一功能,使其能够自动滚动循环播放,并且在数据更新时依然保持流畅的用户体验。

代码实现

我们以直播间的小时榜信息条 为例。由于该场景下的数据更新频率较低,并且滚动不需要过快,而是以固定速度自动翻滚,因此采用UITableView + Timer的方案即可满足需求。

在定时器的选择上,我们使用了Repeat,相比于手动管理Timer的启动和销毁,这种方式更加简洁高效,能够稳定地控制翻滚节奏。

基本UI结构

翻滚条的全部UI就是一个UITableView,但记得设置它不可交互放置用户手动滚动。

Swift 复制代码
class MWVerticalAutoRollView: UIView,UITableViewDelegate,UITableViewDataSource {
    
    /// 滚动列表视图
    private let tableView = UITableView(frame: .zero,style: .plain)
    ....
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addTableView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 添加列表
    private func addTableView() {
        self.addSubview(tableView)
        tableView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
        tableView.backgroundColor = .clear
        tableView.isPagingEnabled = true
        tableView.isScrollEnabled = false
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .none
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }
    
    /// 注册cell 泛型
    /// - Parameter
    func registerCell<T:UITableViewCell>(cell:T.Type) {
        tableView.register(cell, forCellReuseIdentifier: NSStringFromClass(cell))
    }
  1. 创建UITableView的实例,当做上下翻滚的列表。
  2. 设置UITableView的布局,分页,以及禁止滑动事件。
  3. 此外创建了一个对外暴漏的方法用来注册自定义UITableViewCell。

数据处理

想要实现无限的翻滚,以及针对只有一条数据的情况我们首先需要给数据进行处理,主要将第一个数据再次添加到最后一个数据,和轮播一样,以实现假的无限翻滚。

Swift 复制代码
    /// 数据模型数组
    private var dataList:[Any] = []
Swift 复制代码
    /// 设置数据
    /// - Parameter dataList: 数据
    func setData(dataList:[Any]) {
        var results:[Any] = []
        if dataList.count == 0 {
            return
        }
        if dataList.count == 1 {
            results.append(dataList.first!)
            results.append(dataList.first!)
            results.append(dataList.first!)
        }
        if dataList.count == 2 {
            results.append(dataList.first!)
            results.append(dataList.last!)
            results.append(dataList.first!)
        }
        if dataList.count >= 3 {
            results = dataList
            results.append(dataList.first!)
        }
        self.dataList = results
        tableView.reloadData()
        startTimer()
    }

在UITableView的代理方法中,显示dataList数据。

Swift 复制代码
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let delegate = delegate {
            let data = dataList[indexPath.row]
            return delegate.mwVerticalAutoRollView(self, cellForRowAt: indexPath, data: data)
        }
        MWAssert(false, "MWVerticalAutoRollView delegate is nil!")
        return tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    }
    
    func dequeueReusableCell<T:UITableViewCell>(cell:T.Type,indexPath:IndexPath) -> T {
        return tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(cell), for: indexPath) as! T
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 24.0
    }
  1. 数据的数量直接使用dataList.count放回。
  2. UITableView的cell,我们通过代理向该组件内部传递,这样我们可以自定义任何样式的滚动item。
  3. 固定列表高度为24。

实现定时滚动

使用Repeater每2.5秒执行一次,每次切换到下一个row,当切换到最后一个时,隐藏动画直接切换到第一个以实现无线翻滚。

Swift 复制代码
    private func startTimer() {
        self.timer = Repeater.every(.seconds(2.5)) { [weak self] _ in
            guard let self = self else { return }
            DispatchQueue.main.async {
                self.autoScroll()
            }
        }
    }
    
    @objc func autoScroll() {
        currentIndex += 1
        if currentIndex >= dataList.count {
            currentIndex = 0
            // 无动画跳回开头
            CATransaction.begin()
            CATransaction.setDisableActions(true)
            tableView.scrollToRow(at: IndexPath(row: currentIndex, section: 0), at: .top, animated: false)
            CATransaction.commit()
        } else {
            // 平滑滚动到下一行
            tableView.scrollToRow(at: IndexPath(row: currentIndex, section: 0), at: .top, animated: true)
        }
    }
  1. 开始定时器,主线程执行滚动方法。
  2. 每次执行autoScroll()方法,currentIndex+1,滚动到下一行。
  3. 如果已经是最后一行,将currentIndex设置为0,隐藏隐式动画,无动画切换到第一行。

使用示例

组件使用起来非常简单,在需要使用的地方直接创建广播滚动组件MWVerticalAutoRollView的实例,并设置对应布局和数据。

Swift 复制代码
    /// 滚动榜单视图
    private let rollHotListView = MWVerticalAutoRollView()
    
    /// 榜单数据列表
    private var rollHotListDataList = [String]()
Swift 复制代码
    /// 添加滚动榜单视图
    private func addRollHotListView() {
        guard let containerView = self.horSliderContentView else {
            return
        }
        containerView.addSubview(rollHotListView)
        rollHotListView.isHidden = true
        rollHotListView.delegate = self
        rollHotListView.snp.makeConstraints { (make) in
            make.leading.equalToSuperview().offset(16.0)
            make.top.equalToSuperview().offset(MW_TOP_SAFE_HEIGHT + 72)
            make.height.equalTo(24.0)
            make.trailing.equalToSuperview().offset(-16.0)
        }
        rollHotListView.registerCell(cell: MWRollHotListCell.self)
    }
Swift 复制代码
        rollHotListView.setData(dataList: dataList)

实现代理方法,在代理方法中为自定义的WMRollHotListcell渲染数据。

Swift 复制代码
    func mwVerticalAutoRollView(_ view: MWVerticalAutoRollView, cellForRowAt indexPath: IndexPath,data:Any) -> UITableViewCell {
        let cell = view.dequeueReusableCell(cell: MWRollHotListCell.self, indexPath: indexPath)
        if let content = data as? MWRollHotListModel {
            cell.rollHotListModel = content
        }
        cell.selectionStyle = .none
        cell.backgroundColor = .clear
        cell.contentView.backgroundColor = .clear
        return cell
    }

结语

通过使用 UITableView + Timer 实现自动翻滚的广告条或榜单条,我们能够在直播间等场景中,简便且高效地展示动态信息。这个方案既满足了平滑滚动的需求,又避免了频繁的数据更新带来的性能问题。同时,通过简单的定时器控制,我们能够灵活地调整滚动的速度和频率,保证了良好的用户体验。

相关推荐
黑化旺仔4 小时前
【OC】KVO
macos·ios·objective-c·cocoa
HouWan6 小时前
SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息
ios·swiftui·apple
李游Leo6 小时前
HarmonyOS 7 实战开发 05:把页面做到可上线状态
ios·harmonyos
终端安全笔记11 小时前
描述文件、企业证书、MDM 不是三个名字,是三层
android·ios·智能手机
传奇开心果编程12 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
丿Wayne18 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记2 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩2 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年2 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008892 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp