jjzjj

ios - Swift - tableView 行高仅在滚动或切换展开/折叠后更新

coder 2023-09-07 原文

我正在使用 CollapsibleTableView from here并根据我的要求对其进行修改以实现可折叠部分。 Here is how it looks now .

由于根据 UI 设计,我的部分有一个边框,因此我选择了部分标题作为我的 UI 元素,在折叠和展开模式下都保存数据。

原因:我试过了,但无法在下面解释的这个模型中工作 -

** 在部分标题中包含我的标题元素,并在其单元格中包含每个项目的详细信息。默认情况下,该部分处于折叠状态。当用户点击标题时,单元格被切换显示。正如我所说,由于需要向整个部分(点击的标题及其单元格)显示一个边框,因此我选择了部分标题作为我的 UI 操作元素。这是我的 tableView 代码 -

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections.count 
    }

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        switch indexPath.row {
        case 0:
            return sections[indexPath.section].collapsed! ? 0 : (100.0 + heightOfLabel2!)
        case 1:
            return 0
        case 2:
            return 0
        default:
            return 0
        }
    }


func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let header = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier("header") as! CollapsibleTableViewHeader

        if sections.count == 0 {
            self.tableView.userInteractionEnabled = false
            header.cornerRadiusView.layer.borderWidth = 0.0
            header.benefitAlertImage.hidden = true
            header.benefitAlertText.hidden = true
            header.amountLabel.hidden = true
            header.titleLabel.text = "No_Vouchers".localized()
        }
        else {
            header.amountLabel.hidden = false
            header.cornerRadiusView.layer.borderWidth = 1.0
            self.tableView.userInteractionEnabled = true
            header.titleLabel.text = sections[section].name
            header.arrowImage.image = UIImage(named: "voucherDownArrow")
            header.setCollapsed(sections[section].collapsed)

            let stringRepresentation = sections[section].items.joinWithSeparator(", ")

            header.benefitDetailText1.text = stringRepresentation
            header.benefitDetailText2.text = sections[section].shortDesc
            header.benefitDetailText3.text = sections[section].untilDate

            header.section = section
            header.delegate = self

            if sections[section].collapsed == true {
                header.benefitAlertImage.hidden = true
                header.benefitAlertText.hidden = true
            }
            else {
                if sections[section].isNearExpiration == true {
                    header.benefitAlertImage.hidden = false
                    header.benefitAlertText.hidden = false
                }
                else {
                    header.benefitAlertImage.hidden = true
                    header.benefitAlertText.hidden = true
                }
            }

            if appLanguageDefault == "nl" {
                self.totalAmountLabel.text = "€ \(sections[section].totalAvailableBudget)"
            }
            else {
                self.totalAmountLabel.text = "\(sections[section].totalAvailableBudget) €"
            }
        }

        return header
    }

切换折叠/展开的功能 ——
我在部分内使用“动态变化”UILabels 的高度值,然后使用这些值来扩展边框(使用其布局约束)。
func toggleSection(header: CollapsibleTableViewHeader, section: Int) {
        let collapsed = !sections[section].collapsed

        header.benefitAlertImage.hidden = true
        header.benefitAlertText.hidden = true
        // Toggle collapse
        sections[section].collapsed = collapsed
        header.setCollapsed(collapsed)

        // Toggle Alert Labels show and hide
        if sections[section].collapsed == true {
            header.cornerRadiusViewBtmConstraint.constant = 0.0
            header.cornerRadiusViewTopConstraint.constant = 20.0
            header.benefitAlertImage.hidden = true
            header.benefitAlertText.hidden = true
        }
        else {

            heightOfLabel2 = header.benefitDetailText2.bounds.size.height

            if sections[section].isNearExpiration == true {
                header.benefitAlertImage.hidden = false
                header.benefitAlertText.hidden = false
                header.cornerRadiusViewBtmConstraint.constant = -100.0 - heightOfLabel2!
                header.cornerRadiusViewTopConstraint.constant = 10.0
                if let noOfDays = sections[section].daysUntilExpiration {
                    if appLanguageDefault == "nl" {

                        header.benefitAlertText.text = "(nog \(noOfDays) dagen geldig)"
                    }
                    else {
                        header.benefitAlertText.text = "(valable encore \(noOfDays) jour(s))"
                    }
                }                
            }
            else {
                header.cornerRadiusViewBtmConstraint.constant = -80.0 - heightOfLabel2!
                header.cornerRadiusViewTopConstraint.constant = 20.0
                header.benefitAlertImage.hidden = true
                header.benefitAlertText.hidden = true
            }
        }

        // Adjust the height of the rows inside the section
        tableView.beginUpdates()
        for i in 0 ..< sections.count {
            tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: i, inSection: section)], withRowAnimation: .Automatic)
        }
        tableView.endUpdates()
    }

问题:
根据某些条件,我需要在第一次启动 View 时默认扩展此表 View 中的几个部分标题。当我计算标签的高度并使用高度设置边框的顶部和底部约束时,按照设计显示扩展部分标题变得困难。

内容超出边界,因为我的 UILabel 的高度默认为 21。

更新 :仅在我滚动浏览 View 或在折叠/展开之间切换时,行高才会更改

问题:
如何在第一次启动 View 时计算我的部分标题中存在的 UILabels 的高度? (这意味着,在我的 REST 调用完成后,获取数据,然后我需要获取 UIlabel 高度)。

目前,我正在使用 heightOfLabel2 = header.benefitDetailText2.bounds.size.height
(或者)

有没有更好的方法来实现这一目标?

提前致谢!

最佳答案

以下是我根据我对 OP 总体目标的理解所做的工作。如果我误解了,以下仍然是一个有效的例子。完整的工作项目也链接如下。

目标:

  • 动态大小的 TableViewCells 也是
  • 可折叠以显示/隐藏其他详细信息

  • 我尝试了许多不同的方法,这是我唯一可以工作的方法。

    概述

    设计利用了以下内容:
  • 自定义 TableViewCells
  • 自动布局
  • TableView 自动标注

  • 因此,如果您不熟悉这些(尤其是 Autolayout,可能想先回顾一下。

    动态 TableViewCells

    界面生成器

    布置你的原型(prototype)单元格。增加行高大小是最简单的。只需从几个元素开始,以确保您可以使其正常工作。 (即使添加到自动布局可能会很痛苦)。例如,只需垂直堆叠两个标签,布局的全宽。为“标题”制作顶部标签 1 行,为“详细信息”制作第二个 0 行

    重要提示:要将标签和文本区域配置为增长到其内容的大小,您必须将标签设置为 0 行,并将文本区域设置为不可滚动。这些是适合内容的触发器。

    最重要的是确保每个元素的所有四个边都有一个约束。这对于使自动尺寸标注工作至关重要。

    可折叠单元

    接下来,我们为该表格单元原型(prototype)制作一个非常基本的自定义类。将标签连接到自定义单元类中的导出。前任:
    class CollapsableCell: UITableViewCell {
    
      @IBOutlet weak var titleLabel: UILabel!
      @IBOutlet weak var detailLabel: UILabel!
    
    }
    

    简单地从两个标签开始是最简单的。

    还要确保在 Interface Builder 中将原型(prototype)单元类设置为 CollapsableCell 并为其提供重用 ID。

    CollapsableCellViewController

    转到 ViewController。首先是自定义 TableViewCell 的标准内容:
      override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
      }
    
    
      override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "collapsableCell", for: indexPath) as! CollapsableCell
        let item = data[indexPath.row]
    
        cell.titleLabel?.text = item.title
        cell.detailLabel?.text = item.detail
    
        return cell
      }
    

    我们添加了函数来返回行数并使用我们的自定义单元格返回给定行的单元格。希望一切都直截了当。

    现在通常会有另外一个函数,TableView(heightForRowAt:),这将是必需的,但不要添加它(如果你有它,也不要添加它)。这就是 Auto Dimension 的用武之地。将以下内容添加到 viewDidLoad:
      override func viewDidLoad() {
        ...
        // settings for dynamic resizing table cells
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 50
        ...
      }
    

    此时,如果您将细节标签设置为上述 0 行并运行该项目,您应该根据您在该标签中放置的文本量获得不同大小的单元格。那个 Dynamic TableViewCells 就完成了。

    可折叠单元格

    要添加折叠/展开功能,我们可以建立我们目前正在使用的动态大小调整。将以下函数添加到 ViewController:
      override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
        guard let cell = tableView.cellForRow(at: indexPath) as? CollapsableCell else { return }
        let item = data[indexPath.row]
    
        // update fields
        cell.detailLabel.text = self.isExpanded[indexPath.row] ? item.detail1 : ""
    
        // update table
        tableView.beginUpdates()
        tableView.endUpdates()
    
        // toggle hidden status
        isExpanded[indexPath.row] = !isExpanded[indexPath.row]
    
      }
    

    还将“var isExpanded = Bool”添加到您的 ViewController 以存储您的行的当前扩展状态(这也可以是您自定义 TableViewCell 中的类变量)。

    构建并单击其中一行,它应该缩小以仅显示标题标签。这就是基础。

    示例项目:
    可以在 github 获得具有更多字段和公开 V 字形图像的工作示例项目。 .这还包括一个单独的 View ,其中包含一个基于内容动态调整大小的 Stackview 演示。

    一些注意事项:
  • 这都是在普通的 TableViewCell 中完成的。我知道 OP 正在使用标题单元格,虽然我想不出为什么它不能以相同的方式工作,但没有必要这样做。
  • 添加和删​​除 subview 是我最初认为最有效的方法,因为 View 可以从 Nib 加载,甚至可以存储以备重新添加。出于某种原因,我无法在添加 subview 后调整其大小。我想不出它不起作用的原因,但这里有一个解决方案。
  • 关于ios - Swift - tableView 行高仅在滚动或切换展开/折叠后更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44718598/

    有关ios - Swift - tableView 行高仅在滚动或切换展开/折叠后更新的更多相关文章

    1. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

      我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

    2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

      这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

    3. Ruby 文件 IO 定界符? - 2

      我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

    4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

      1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

    5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

      print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

    6. ruby-on-rails - NameError(未初始化常量 Unzipper::Zip)但仅在 Heroku 部署(Rails)上 - 2

      我有一个类unzipper.rb,它使用Rubyzip解压文件。在我的本地环境中,我可以成功解压缩文件,而无需使用require'zip'明确包含依赖项但是在Heroku上,我得到一个NameError(uninitializedconstantUnzipper::Zip)我只能通过使用明确的require来解决问题:为什么这在H​​eroku环境中是必需的,但在本地主机上却不是?我的印象是Rails自动需要所有gem。app/services/unzipper.rbrequire'zip'#OnlyrequiredforHeroku.Workslocallywithout!class

    7. ruby-on-rails - 仅在某些页面上使用 rails_xss - 2

      我正在使用rails_xss运行Rails2.3.14插入。我有另一个用于创建管理仪表板View的插件。我的问题是rails_xss正在转义我的仪表板插件生成的所有HTML。有没有一种方法可以将rails_xss配置为不转义匹配example.com/admin或基于目录(app/views/admin)或任何类似的页面结果一样吗? 最佳答案 更新仪表板生成插件以使用raw或html_safe进行内容输出可能会更简单。 关于ruby-on-rails-仅在某些页面上使用rails_xss

    8. ruby - 为 IO::popen 拯救 "command not found" - 2

      当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

    9. ruby-on-rails - 语言环境不在 Rails 4 中切换 - 2

      我的Rails应用程序在rails4.0.2上,我在使用locale变量和params[:locale]切换翻译时遇到问题官方railsguide.我在mysite有一个单页网站.我的国际化路线:scope"(:locale)",locale:/en|de/do#myrouteshereend我的应用程序Controllerbefore_filter:set_localedefset_localeI18n.locale=params[:locale]||I18n.default_locale#Rails.application.routes.default_url_options[:l

    10. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

      当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

    随机推荐