gpt4 book ai didi

ios - ios-TableView内的动画扩展TableView(在第一行上点击)

转载 作者:行者123 更新时间:2023-11-28 05:50:03 30 4
gpt4 key购买 nike

我正在构建类似待办事项应用程序的东西,其中在“主” UITableView内包含可扩展的“从属” UITableViewCell(原因是“可扩展的“从属”表的材料设计”)。可能所有这些都位于UIViewUIScrollView中嵌入的NavigationViewController内的一个容器TabViewController中,这可能也很相关。非常复杂...让我解释一下:

  • 具有两个部分(今年/长期)的“Master” UITableViewControler,带有自定义标题和自定义TableViewCell
  • 自定义TableViewCell里面有一个UIView和一个“slave” UITableView-底层UIView被限制为“slave” UITableView,并使其具有阴影的“材料”设计(cropToBounds防止UITableView上出现阴影)
  • “Slave” UITableView应该只包含一个扩展部分(我遵循这个人的逻辑:https://www.youtube.com/watch?v=ClrSpJ3txAs)–点击第一行隐藏/显示子视图和页脚
  • “从属” UITableView具有3个自定义TableViewCell(“标头”始终填充在第一行,“子任务”始终填充在第二行,并根据子任务的数量填充,“页脚”始终填充在最后))

  • 到目前为止,丑陋的UI的图片可能会使其更加清晰:

    Interface Builder setup

    UI design

    我正在尝试尽可能多地使用Interface Builder(对我来说,作为一个初学者,它节省了大量代码,并使事情变得更清楚)。

    在代码方面,它有点复杂,因为我有一个“目标”领域对象,每次都有“子任务”对象列表。因此,“主” UITableViewController数据源抓住了一个目标,并将其传递给作为数据源的“主” TableViewCell(GoalMainCell) cell.goal = goals?[indexPath.row],并为其出口“从” UITableView委托。这样,我可以使用领域中正确的子任务填充“从属” UITableView

    当我尝试将两个表的数据源和委托人作为 UITableViewController的主对象时,我无法正确填充子任务(即使为每串 tableView.tag语句都设置 if…else,因为 indexPath.row自启动以来就不能被视为目标的索引从0开始,每个“slave” tableView.row)

    类的GoalsTableViewController:UITableViewController:(主tableviewcontroller)
    let realm = try! Realm()
    var goals: Results<Goal>?
    var parentVc : OurTasksViewController?
    var numberOfSubtasks: Int?

    let longTermGoalsCount = 0

    @IBOutlet var mainTableView: UITableView!
    @IBOutlet weak var noGoalsLabel: UILabel!

    override func viewDidLoad() {
    super.viewDidLoad()
    loadGoals()
    }

    override func viewDidAppear(_ animated: Bool) { // MUST be viewDidAppear
    super.viewDidAppear(true)
    parentVc = self.parent as? OurTasksViewController
    }

    func loadGoals() {
    goals = realm.objects(Goal.self)
    if goals?.count == 0 || goals?.count == nil { noGoalsLabel.isHidden = false }
    tableView.reloadData()
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
    if longTermGoalsCount > 0 {
    //TODO: split goals to "this year" and "future" and show second section if future has some goals
    return 2
    } else {
    return 1
    }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return goals?.count ?? 0
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "GoalMainCell", for: indexPath) as! GoalsMainCell
    cell.goal = goals?[indexPath.row] //send goal in to the GoalMainCell controller
    cell.layoutIfNeeded()
    return cell

    }

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ThisYearGoalsHeaderTableViewCell") as! ThisYearGoalsHeaderTableViewCell
    cell.layoutIfNeeded()
    return cell
    } else {
    let cell = tableView.dequeueReusableCell(withIdentifier: "LongTermGoalsHeaderCell")!
    cell.layoutIfNeeded()
    return cell
    }
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
    }

    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 44
    }

    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return UITableView.automaticDimension
    }

    override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
    return 44
    }

    类GoalsMainCell:UITableViewCell (主表的自定义单元格)
    @IBOutlet weak var goalsSlaveTableView: GoalsSlaveTableView! 

    let realm = try! Realm()
    var subtasks: Results<GoalSubtask>?
    var numberOfRows: Int = 0
    var goal: Goal? { //goal passed from master tableView
    didSet {
    loadSubtasks()
    }
    }

    func loadSubtasks() {
    subtasks = goal?.subtasks.sorted(byKeyPath: "targetDate", ascending: true)
    guard let expanded = goal?.expanded else {
    numberOfRows = 1
    return
    }
    if expanded {
    numberOfRows = (subtasks?.count ?? 0) + 2
    } else {
    numberOfRows = 1
    }
    }

    扩展GoalsMainCell:UITableViewDataSource (主表的自定义单元格)
    func numberOfSections(in tableView: UITableView) -> Int { return 1 }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return numberOfRows
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if indexPath.row == 0 {
    let cell = tableView.dequeueReusableCell(withIdentifier: "GoalsSlaveTableViewHeaderCell", for: indexPath) as! GoalsSlaveTableViewHeaderCell
    cell.goalNameLabel.text = goal?.name ?? "No task added"
    cell.layoutIfNeeded()
    return cell
    } else if indexPath.row > 0 && indexPath.row < numberOfRows - 1 {
    let cell = tableView.dequeueReusableCell(withIdentifier: "GoalsSlaveTableViewCell", for: indexPath) as! GoalsSlaveTableViewCell
    cell.subTaskNameLabel.text = subtasks?[indexPath.row - 1].name //because first row is main goal name
    cell.layoutIfNeeded()
    return cell
    } else {
    let cell = tableView.dequeueReusableCell(withIdentifier: "GoalsSlaveTableViewFooterCell", for: indexPath) as! GoalsSlaveTableViewFooterCell
    cell.layoutIfNeeded()
    return cell
    }
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 44
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 0
    }

    func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
    return 0
    }

    扩展GoalsMainCell:UITableViewDelegate (主表的自定义单元格)
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.row == 0 {
    if goal != nil {
    do {
    try realm.write {
    goal!.expanded = !goal!.expanded
    }
    } catch {
    print("Error saving done status, \(error)")
    }
    }
    }
    let section = IndexSet.init(integer: indexPath.section)
    tableView.reloadSections(section, with: .none)

    tableView.deselectRow(at: indexPath, animated: true)
    }

    类GoalsSlaveTableView:UITableView (从属tableViewController)
    override func layoutSubviews() {
    super.layoutSubviews()
    self.layer.cornerRadius = cornerRadius
    }

    override var intrinsicContentSize: CGSize {
    self.layoutIfNeeded()
    return self.contentSize
    }

    override var contentSize: CGSize {
    didSet{
    self.invalidateIntrinsicContentSize()
    }
    }

    类GoalsSlaveTableViewCell:UITableViewCell (从属表的单元格)
    @IBOutlet weak var subTaskNameLabel: UILabel!
    @IBOutlet weak var subTaskTargetDate: UILabel!
    @IBOutlet weak var subTaskDoneImage: UIImageView!

    类GoalsSlaveTableViewHeaderCell:UITableViewCell (从属表的标题-实际上也是自定义单元格)
    @IBOutlet weak var goalNameLabel: UILabel!
    @IBOutlet weak var goalTargetDate: UILabel!
    @IBOutlet weak var goalProgressBar: UIProgressView!

    类GoalsSlaveTableViewFooterCell:UITableViewCell (和从属页脚)
    @IBAction func deleteGoalButtonTapped(_ sender: UIButton) {
    print("Delete goal")
    }

    @IBAction func editGoalButtonTapped(_ sender: UIButton) {
    print("Edit goal")
    }

    问题:展开/折叠后,如何调用带有动画(如果需要的话)表视图的重新加载数据?

    从外观上看,我几乎可以正常使用它。丢失的唯一且可能是最棘手的事情是在扩展/折叠时自动重新加载/调整“主”单元和“从” tableView的大小。换句话说:当我点击“slave”表中的第一行时,Realm中的数据将被更新(“expanded” bool属性),但是我必须终止应用程序并再次启动以设置布局(我认为viewDidLoad必须跑)。我只是从中获得了一些灵感,但我发现 没有链接可以解释 如何在运行时期间扩展/折叠以及使用漂亮的动画调用两者的大小:

    Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
    Is it possible to implement tableview inside tableview cell in swift 3?

    Is it possible to add UITableView within a UITableViewCell

    TableView inside tableview cell swift 3

    TableView Automatic Dimension Tableview Inside Tableview

    Reload a tableView inside viewController

    作为一个初学者,我可能会犯一些非常简单的错误,例如在IB中缺少一些自动布局约束,因此调用 invalidateIntrinsicContentSize()…也许使用这种架构,无法进行动画式平滑表重新加载,因为总是会发生“重新加载”冲突...?希望那里有人可以帮助我。感谢您的任何帮助!

    最佳答案

    我解决了动画/更新。

    1)我忘记更改.expanded属性后重新加载数据:

    扩展GoalsMainCell:UITableViewDelegate

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let goalNotificationInfo = ["index" : goalIndex ]
    if indexPath.row == 0 {
    if goal != nil {
    do {
    try realm.write {
    goal!.expanded = !goal!.expanded
    }
    } catch {
    print("Error saving done status, \(error)")
    }
    }
    loadSubtasks()
    tableView.deselectRow(at: indexPath, animated: true)

    let section = IndexSet.init(integer: indexPath.section)
    tableView.reloadSections(section, with: .none)

    NotificationCenter.default.post(name: .goalNotKey, object: nil, userInfo: goalNotificationInfo as [AnyHashable : Any])
    }



    }

    2)我向从属表委托添加了通知观察器,并调用 .beginUpdate() + .endUpdate()
    @objc func updateGoalSection(_ notification: Notification) {

    tableView.beginUpdates()

    tableView.endUpdates()

    }

    现在,更新可以顺利过渡。在粗略解决方案中,这揭示了索引编制和主调用自动尺寸的另一个问题,但这是另一个主题。

    希望它能帮助其他人减少挣扎。

    关于ios - ios-TableView内的动画扩展TableView(在第一行上点击),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53266333/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com