您的位置:首页 > 新闻 > 会展 > IOS 26 实现歌单详情(UITableView)列表 ③

IOS 26 实现歌单详情(UITableView)列表 ③

2025/6/2 20:35:51 来源:https://blog.csdn.net/sziitjin/article/details/142327074  浏览:    关键词:IOS 26 实现歌单详情(UITableView)列表 ③

 歌单详情完整效果

歌单列表分组头部效果

 

本节是在文章 IOS 25 实现歌单详情(UITableView)列表② 的基础上,实现歌单列表分组头部View。当歌单列表滑动头部View至顶部时,头部View不会因列表滑动而消失,会一直显示在顶部。故,使用UITableViewHeaderFooterView 来实现。

实现逻辑

将歌单详情分为两组,图1为1组,图2为1组,每组都包含头部View(UITableViewHeaderFooterView);图1不需要头部View,则设置头部View隐藏,图2头部View在滚动歌单列表到顶部时,头部View会固定在顶部不消失。

歌单列表头部View实现

实现流程:
1.创建UITableViewHeaderFooterView,及在使用UITableView的Controller控制器上注册;

2.获取data分组数据,并调用UITableView的reloadData(),将数据更新到列表;

3.将data的Item数据绑定UITableView的每一个Section。

1)创建和注册HeaderFooterView

从效果图上面可以看出,歌单列表头部View由一个水平方向布局包含UIImageView和UITableView来实现。

自定义SongGroupHeaderView,继承自BaseTableViewHeaderFooterView,设置TGLinearLayout为水平方向。


class SongGroupHeaderView : BaseTableViewHeaderFooterView{static let NAME = "SongGroupHeaderView"override func initViews() {super.initViews()backgroundColor = .colorBackgroundLightcontentView.backgroundColor = .colorBackgroundLightcontainer.tg_gravity = TGGravity.vert.centercontainer.tg_padding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: PADDING_SMALL)}override func getContainerOrientation() -> TGOrientation {return .horz}}

添加图标、全部播放文本和歌曲数量等布局,添加头部点击事件,并绑定布局数据。

//
//  SongGroupHeaderView.swift
//  MyCloudMusic
//
//  Created by jin on 2024/9/13.
//import UIKit
import TangramKitclass SongGroupHeaderView : BaseTableViewHeaderFooterView{static let NAME = "SongGroupHeaderView"var countView:UILabel!/// 播放所有点击var playAllClick:(()->Void)!override func initViews() {super.initViews()backgroundColor = .colorBackgroundLightcontentView.backgroundColor = .colorBackgroundLightcontainer.tg_gravity = TGGravity.vert.centercontainer.tg_padding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: PADDING_SMALL)let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(onPlayAllTouchEvent(_:)))//将触摸事件添加到当前viewcontainer.addGestureRecognizer(tapGestureRecognizer)//左侧容器let leftContainer = TGRelativeLayout()leftContainer.tg_width.equal(50)leftContainer.tg_height.equal(50)container.addSubview(leftContainer)//图标let iconView = UIImageView()iconView.tg_width.equal(30)iconView.tg_height.equal(30)iconView.tg_centerX.equal(0)iconView.tg_centerY.equal(0)iconView.image = R.image.playCircle()?.withTintColor()iconView.tintColor = .colorPrimaryleftContainer.addSubview(iconView)//播放全部提示文本let titleView = UILabel()titleView.tg_width.equal(.wrap)titleView.tg_height.equal(.wrap)titleView.text = R.string.localizable.playAll()titleView.font = UIFont.boldSystemFont(ofSize: TEXT_LARGE2)titleView.textColor = .colorOnSurfacecontainer.addSubview(titleView)//数量countView = UILabel()countView.tg_width.equal(.fill)countView.tg_height.equal(.wrap)countView.text = "0"countView.textAlignment = .leftcountView.font = UIFont.systemFont(ofSize: TEXT_MEDDLE)countView.textColor = .black80container.addSubview(countView)//下载按钮let downloadButton = ViewFactoryUtil.button(image:R.image.arrowCircleDown()!.withTintColor())downloadButton.tintColor = .colorOnSurfacedownloadButton.tg_width.equal(50)downloadButton.tg_height.equal(50)container.addSubview(downloadButton)//多选按钮let multiSelectButton = ViewFactoryUtil.button(image:R.image.moreVerticalDot()!.withTintColor())multiSelectButton.tintColor = .colorOnSurfacemultiSelectButton.tg_width.equal(50)multiSelectButton.tg_height.equal(50)container.addSubview(multiSelectButton)}override func getContainerOrientation() -> TGOrientation {return .horz}@objc func onPlayAllTouchEvent(_ recognizer:UITapGestureRecognizer) {playAllClick()}func bind(_ data:SongGroupData) {countView.text = "(\(data.datum.count))"}
}

BaseTableViewHeaderFooterView实现 

//
//  BaseTableViewHeaderFooterView.swift
//  TableViewHeaderFooterView基类
//
//  Created by jin on 2024/9/13.
//import TangramKit
import UIKitclass BaseTableViewHeaderFooterView: UITableViewHeaderFooterView {// 对于需要动态评估高度的UITableViewCell来说可以把布局视图暴露出来。用于高度评估和边界线处理。以及事件处理的设置。var container: TGBaseLayout!override init(reuseIdentifier: String?) {super.init(reuseIdentifier: reuseIdentifier)innerInit()}required init?(coder: NSCoder) {super.init(coder: coder)innerInit()}func innerInit() {initViews()initDatum()initListeners()}/// 找控件func initViews() {backgroundColor = .clearcontentView.backgroundColor = .clearcontainer = TGLinearLayout(getContainerOrientation())container.tg_width.equal(.fill)container.tg_height.equal(.wrap)contentView.addSubview(container)}/// 设置数据func initDatum() {}/// 设置监听器func initListeners() {}/// 获取根容器布局方向func getContainerOrientation() -> TGOrientation {return .vert}/// 使用MyLayout后,让item自动计算高度,要重写该方法override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {return container.systemLayoutSizeFitting(targetSize)}
}

在SheetDetailController控制器,注册SongGroupHeaderView

class SheetDetailController: BaseTitleController {override func initViews() {super.initViews()title = R.string.localizable.sheet()// 注册单曲tableView.register(SongItemCell.self, forCellReuseIdentifier: Constant.CELL)tableView.register(SheetInfoCell.self, forCellReuseIdentifier: SheetInfoCell.NAME)//注册sectiontableView.register(SongGroupHeaderView.self, forHeaderFooterViewReuseIdentifier: SongGroupHeaderView.NAME)tableView.bounces = false}
}
2)获取data分组列表数据

定义分组列表数据模型SongGroupData

//
//  SongGroupData.swift
//  音乐分组模型
//
//  Created by jin on 2024/9/13.
//import Foundationclass SongGroupData: BaseModel {var datum:Array<Any>!
}

请求歌单详情接口获取歌单详情里的歌曲列表数据,组装成分组数据,更新tableView.reloadData()

class SheetDetailController: BaseTitleController {override func initDatum() {super.initDatum()loadData()}func loadData() {DefaultRepository.shared.sheetDetail(id).subscribeSuccess { [weak self] data inself?.show(data.data!)}.disposed(by: rx.disposeBag)}func show(_ data: Sheet) {self.data = data//第一组var groupData = SongGroupData()groupData.datum = [data]datum.append(groupData)//第二组if let r = data.songs {if !r.isEmpty {//有音乐才设置//设置数据groupData = SongGroupData()groupData.datum = rdatum.append(groupData)superFooterContainer.backgroundColor = .colorLightWhite}}tableView.reloadData()}
}
3)Item数据绑定Section

SheetDetailController控制器扩展父类的实现UITableViewDataSource:

1)实现numberOfSections方法,返回分组数量,即有多少组;

2)重写numberOfRowsInSection方法,返回每个分组内的列表长度,即当前组有多少个; 

3)实现viewForHeaderInSection方法,创建对应的HeaderView,并将分组数据绑定到HeaderView。

4)重写cellForRowAt方法,创建对应的Cell,并将分组数据内的列表的Item数据绑定到Cell。

extension SheetDetailController {/// 有多少组func numberOfSections(in tableView: UITableView) -> Int {return datum.count}/// 当前组有多少个override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {let data = datum[section] as! SongGroupDatareturn data.datum.count}/// 返回section viewfunc tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {//取出组数据let groupData = datum[section] as! SongGroupData//获取headerlet header  = tableView.dequeueReusableHeaderFooterView(withIdentifier: SongGroupHeaderView.NAME) as! SongGroupHeaderViewheader.bind(groupData)header.playAllClick = {[weak self] inlet groupData = self?.datum[1] as! SongGroupDataself?.play(groupData.datum[0] as! Song)}return header}override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {let groupData = datum[indexPath.section] as! SongGroupDatalet data = groupData.datum[indexPath.row]let type = typeForItemAtData(data)switch type {case .sheet:let cell = tableView.dequeueReusableCell(withIdentifier: SheetInfoCell.NAME, for: indexPath) as! SheetInfoCellcell.bind(data as! Sheet)return celldefault:let cell = tableView.dequeueReusableCell(withIdentifier: Constant.CELL, for: indexPath) as! SongItemCellcell.bind(data as! Song)cell.indexView.text = "\(indexPath.row + 1)"return cell}}/// header高度func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {if section == 1 {return 50}//其他组不显示sectionreturn 0}
}

 至此,实现了歌单列表分组头部效果。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com