如何快速制作嵌套的可折叠 uitableview?
Posted
技术标签:
【中文标题】如何快速制作嵌套的可折叠 uitableview?【英文标题】:How to make nested collapsible tableview i swift? 【发布时间】:2021-08-20 09:04:28 【问题描述】:我有一些设计,其中父母和他们的孩子都是可折叠的。我已经使用表格视图实现了父级,但是对于它的子级,我将如何实现它的扩展单元格。我应该加载另一个自定义视图单元格还是应该更改当前单元格,我不知道。如果有人对此有任何想法,请帮助我。
// Model Class
class WorkoutTemplate
var folderName:String
var workoutType: [WorkoutType]
init(folderName: String, workoutType: [WorkoutType])
self.folderName = folderName
self.workoutType = workoutType
class WorkoutType
var workoutCategoryName: String // Basic Full Body
var totalWorkouts : [Workout]
init(workoutCategoryName: String, totalWorkouts: [Workout] )
self.workoutCategoryName = workoutCategoryName
self.totalWorkouts = totalWorkouts
class Workout
var workoutName: String
var reps:Int = 0
var sets:Int = 0
init(workoutName: String, reps: Int, sets: Int)
self.workoutName = workoutName
self.reps = reps
self.sets = sets
// Controller class
import UIKit
class AddWorkoutViewController: UIViewController
@IBOutlet weak var tableView: UITableView?
var data = [WorkoutTemplate]()
var sectionIsExpanded = [false, false, false]
private let headerIdentifier = "WorkoutTemplateHeaderCell"
private let cellIdentifier = "AddWorkoutCategoryCell"
override func viewDidLoad()
super.viewDidLoad()
let workout = Workout(workoutName: "Squat", reps: 10, sets: 9)
let workout2 = Workout(workoutName: "Bench press", reps: 6, sets: 7)
let workout3 = Workout(workoutName: "Dunmbell lunge", reps: 12, sets: 78)
let workoutType = WorkoutType(workoutCategoryName: "Basic full body", totalWorkouts: [workout, workout2, workout3])
let workoutTemplate = WorkoutTemplate(folderName: "My Workout Template", workoutType: [workoutType, workoutType])
data.append(workoutTemplate)
data.append(workoutTemplate)
data.append(workoutTemplate)
tableView?.reloadData()
extension AddWorkoutViewController: UITableViewDataSource, UITableViewDelegate
func numberOfSections(in tableView: UITableView) -> Int
return data.count
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// First will always be header
let sectiondata = data[section]
return sectionIsExpanded[section] ? (sectiondata.workoutType.count + 1) : 1
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if indexPath.row == 0
let headerCell = tableView.dequeueReusableCell(withIdentifier: headerIdentifier, for: indexPath) as! AddWorkoutTemplateHeaderTableViewCell
let sectionData = data[indexPath.section]
headerCell.headingLabel?.text = sectionData.folderName
if sectionIsExpanded[indexPath.section]
headerCell.setExpanded()
else
headerCell.setCollapsed()
return headerCell
else
let catCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! AddWorkoutCategoryTableViewCell
let sectionData = data[indexPath.section]
let rowData = sectionData.workoutType[(indexPath.row - 1)]
catCell.headingLabel?.text = rowData.workoutCategoryName
var subHeadings = ""
for item in rowData.totalWorkouts
subHeadings = subHeadings + item.workoutName + ", "
catCell.mutiWorkoutLabel?.text = subHeadings
return catCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
// Expand/hide the section if tapped its header
if indexPath.row == 0
sectionIsExpanded[indexPath.section] = !sectionIsExpanded[indexPath.section]
tableView.reloadSections([indexPath.section], with: .automatic)
【问题讨论】:
【参考方案1】:因为你有“通用”元素——人字形图像、标题、...
和“开始锻炼”按钮,我建议使用单个单元格类而不是单独的类。
将“中心”元素放在垂直堆栈视图中:
当你想显示单元格“折叠”集时:
collapsedView.isHidden = false
expandedView.isHidden = true
并显示单元格“展开”:
collapsedView.isHidden = true
expandedView.isHidden = false
堆栈视图会自动移除隐藏视图占用的空间,但将其保留为视图层次结构的一部分,因此您不必添加/删除子视图和激活/停用约束。
这是一个示例布局:
以及它在运行时的样子:
【讨论】:
谢谢,@DonMag 我更可能得到你的回答【参考方案2】://
// AddWorkoutViewController.swift
//
// Created by developer on 6/1/21.
//
import UIKit
class AddWorkoutViewController: UIViewController, passIndexData
@IBOutlet weak var tableView: UITableView?
var data = [WorkoutTemplate]()
var sectionIsExpanded = [false, false, false]
private let headerIdentifier = "WorkoutTemplateHeaderCell"
private let cellIdentifier = "AddWorkoutCategoryCell"
override func viewDidLoad()
super.viewDidLoad()
let workout = Workout(workoutName: "Squat", reps: 10, sets: 9)
let workout2 = Workout(workoutName: "Bench press", reps: 6, sets: 7)
let workout3 = Workout(workoutName: "Dunmbell lunge", reps: 12, sets: 78)
let workoutType = WorkoutType(workoutCategoryName: "Basic full body", totalWorkouts: [workout, workout2, workout3])
let workoutType2 = WorkoutType(workoutCategoryName: "Basic full body", totalWorkouts: [workout, workout2, workout3])
let workoutTemplate = WorkoutTemplate(folderName: "My Workout Template", workoutType: [workoutType, workoutType2])
let workoutType3 = WorkoutType(workoutCategoryName: "Basic full body", totalWorkouts: [workout, workout2, workout3])
let workoutType4 = WorkoutType(workoutCategoryName: "Basic full body", totalWorkouts: [workout, workout2, workout3])
let workoutTemplate2 = WorkoutTemplate(folderName: "My Workout Template", workoutType: [workoutType3, workoutType4])
data.append(workoutTemplate)
data.append(workoutTemplate2)
//data.append(workoutTemplate)
tableView?.reloadData()
func stringToAtributedString(string:String, fontName: String, alpha: CGFloat = 1)-> NSMutableAttributedString
if let safeFont = UIFont(name: fontName, size: 14)
let color = UIColor(named: "textBlack")
color?.withAlphaComponent(alpha)
let attribute = [NSAttributedString.Key.font: safeFont, NSAttributedString.Key.foregroundColor: color]
let attributedString = NSMutableAttributedString(string: string, attributes: attribute)
return attributedString
return NSMutableAttributedString()
extension AddWorkoutViewController: UITableViewDataSource, UITableViewDelegate
func numberOfSections(in tableView: UITableView) -> Int
return data.count
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
return 1.2 //.leastNormalMagnitude // 0 may not work
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// First will always be header
let sectiondata = data[section]
return sectionIsExpanded[section] ? (sectiondata.workoutType.count + 1) : 1
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if indexPath.row == 0
// header cell
let headerCell = tableView.dequeueReusableCell(withIdentifier: headerIdentifier, for: indexPath) as! AddWorkoutTemplateHeaderTableViewCell
let sectionData = data[indexPath.section]
headerCell.headingLabel?.text = sectionData.folderName
if sectionIsExpanded[indexPath.section]
headerCell.setExpanded()
else
headerCell.setCollapsed()
headerCell.selectionStyle = .none
return headerCell
else
// workout category cell
let catCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! AddWorkoutCategoryTableViewCell
let sectionData = data[indexPath.section]
let rowData = sectionData.workoutType[(indexPath.row - 1)]
catCell.headingLabel?.text = rowData.workoutCategoryName
var subHeadings = ""
let workoutNames = UILabel()
workoutNames.numberOfLines = 0
workoutNames.alpha = 0.7
for item in rowData.totalWorkouts
subHeadings = subHeadings + item.workoutName + ", "
workoutNames.attributedText = stringToAtributedString(string: subHeadings, fontName: "Poppins-Regular")
if catCell.workoutSetContainer != nil
for view in catCell.workoutSetContainer!.subviews.enumerated()
view.element.removeFromSuperview()
print("section: \(indexPath.section) row: \(indexPath.row) rowCollapse: \(rowData.isExpanded)")
if rowData.isExpanded
catCell.setCollapsed()
for item in rowData.totalWorkouts.enumerated()
let workoutSetcell = tableView.dequeueReusableCell(withIdentifier: "WorkoutSetCell") as! AddworkoutWOrkoutSetTableViewCell
workoutSetcell.workoutNameLabel?.text = item.element.workoutName
//workoutSetcell.workoutSetLabel?.text = "\(item.element.reps)" + " " + "\(item.element.sets)"
let repsCount = stringToAtributedString(string: "\(item.element.reps)", fontName: "Poppins-Bold")
let repsString = stringToAtributedString(string: " reps", fontName: "Poppins-Regular", alpha: 0.7)
repsCount.append(repsString)
workoutSetcell.workoutSetLabel?.attributedText = repsCount
catCell.workoutSetContainer?.addArrangedSubview(workoutSetcell)
else
catCell.setExpanded()
catCell.workoutSetContainer?.addArrangedSubview(workoutNames)
catCell.cellDelegate = self
catCell.cellIndexPath = indexPath
catCell.selectionStyle = .none
return catCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
// Expand/hide the section if tapped its header
if indexPath.row == 0
sectionIsExpanded[indexPath.section] = !sectionIsExpanded[indexPath.section]
tableView.reloadSections([indexPath.section], with: .automatic)
extension AddWorkoutViewController:expandCell
func passIndexValues(indexPath: IndexPath?)
if indexPath != nil
let sectionData = data[indexPath!.section]
let rowData = sectionData.workoutType[indexPath!.row - 1]
rowData.isExpanded = !rowData.isExpanded
sectionData.workoutType[indexPath!.row - 1] = rowData
data[indexPath!.section] = sectionData
tableView?.reloadRows(at: [indexPath!], with: .automatic)
//tableView?.reloadData()
//print("index path \(indexPath?.section)")
【讨论】:
以上是关于如何快速制作嵌套的可折叠 uitableview?的主要内容,如果未能解决你的问题,请参考以下文章