【问题标题】:Animation is weird when hiding subView in UIStackView in Cell在 Cell 的 UIStackView 中隐藏 subView 时动画很奇怪
【发布时间】:2018-06-19 13:56:21
【问题描述】:

情况是这样的。 stackView 中的标题标签、“阅读更多”按钮和内容标签。并且stackView在一个单元格中,设置Auto-Layout。 tableView 的单元格高度设置为 AutoDimension。当我点击按钮时,内容标签将显示或隐藏。

按钮的动作方法是

@IBAction func readMore(_ sender: Any) {
  tableView.performBatchUpdates({
    self.contentLabel.isHidden.toggle()
  }, completion: nil)
}

这是慢动画的结果:

如您所见,当要显示内容时,首先显示第 2 行,即从中心显示内容。当内容要隐藏时,内容标签会立即隐藏,并且按钮会拉伸到内容标签隐藏前的框架。这个动画很奇怪。

此外,如果我将 stackView 的间距设置为 10,情况会变得更糟。标题标签也受到影响:

我调整了一切,stackView的分布,三个subView的内容模式和内容拥抱/压缩优先级。我找不到合适的方法来解决它。

这是理想的结果:

我通过一个小技巧实现了它:

@IBAction func readMore(_ sender: Any) {
  tableView.performBatchUpdates({
    UIView.animate(withDuration: 0.3) { // It must be 0.3
      self.contentLabel.isHidden.toggle()
    }
  }, completion: nil)
}

我不确定这是修复它的最合适方法。所以我想知道为什么会出现这种奇怪的动画,以及是否有更合适的方法来修复它。谢谢!

【问题讨论】:

  • 您是否尝试过切换堆栈视图本身的可见性?
  • 你为什么打电话给beginUpdatesendUpdates,中间什么都没有?
  • @shim 这将调用 tableView 来调整单元格的高度。在它们之间移动isHidden.toggle()是完全一样的,以及移动到tableView.performBatchUpdates的闭包。
  • Documentation 表示尽可能使用performBatchUpdates
  • @shim 我知道。但它没有改变动画。为了不误导他人,我将在上面编辑我的代码。谢谢。

标签: ios swift


【解决方案1】:

我以前做过几次类似的动画。解决此问题的方法是定义堆栈视图的高度并独立地定义单元格的内容视图。然后当你想要改变单元格的高度时,你只需要更新内容视图的高度约束。

确定视图高度的一个好方法是使用intrinsicContentSize 属性。如果您需要与继承的值不同的值,请覆盖此值。

通知视图大小更改的另一种方法是创建一个带有委托或闭包的子类,该子类从子类视图frame 属性中调用,并将新大小传递给监听它的人。

【讨论】:

    【解决方案2】:

    隐藏/显示多行标签的动画可能会出现问题,尤其是在堆栈视图中使用时。

    如果你试一试,你会发现即使在表格视图单元的外部 - 只是视图中的堆栈视图 - 在切换 .isHidden 时你会看到同样的问题标签的属性。这是因为UILabel 垂直居中它的文本。

    这是另一种方法,它不使用堆栈视图(背景颜色为清晰起见):

    顶部标签设置为 1 行;阅读更多是一个普通按钮,底部标签设置为0行。

    您会注意到粉红色的矩形。那是UIView,我将其命名为ShimView - 稍后会详细介绍。

    顶部标签被限制Top: 4, Leading: 8, Trailing: 8 按钮受约束Top: 0 (to topLabel), Leading: 8, Trailing: 8 底部标签受约束Top: 0 (to button), Leading: 8, Trailing: 8

    “垫片视图”受到限制Trailing: 8, Top: 0 (*to the top of bottom label*), Bottom: 4 (to the contentView)

    “shim 视图”给定了一个高度约束 21Priority: 999 -- 并且该高度约束连接到单元类中的一个 IBOutlet。 p>

    关键是我们将调整 shim 的 Height 约束的 .constant 以展开/折叠单元格。

    在初始化时,我们将 .constant 设置为 0 - 这将使底部标签保持在其由内容确定的高度,但不会可见,因为它将被单元格的 contentView 裁剪。

    当我们想要“显示/隐藏”标签时,我们将为 shim 的高度 .constant 设置动画。

    结果:

    还有,清除背景色后的结果:

    代码如下:

    //
    //  ExpandCollapseTableViewController.swift
    //
    //  Created by Don Mag on 6/19/18.
    //
    
    import UIKit
    
    class ExpandCollapseCell: UITableViewCell {
    
        @IBOutlet var topLabel: UILabel!
        @IBOutlet var theButton: UIButton!
        @IBOutlet var bottomLabel: UILabel!
        @IBOutlet var theShim: UIView!
        @IBOutlet var shimHeightConstraint: NSLayoutConstraint!
    
        var myCallBack: (() -> ())?
    
        @IBAction func didTap(_ sender: Any) {
            myCallBack?()
        }
    
    }
    
    class ExpandCollapseTableViewController: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.rowHeight = UITableViewAutomaticDimension
            tableView.estimatedRowHeight = 100
        }
    
        override func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 4
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandCollapseCell", for: indexPath) as! ExpandCollapseCell
    
            cell.topLabel.text = "Index Path - \(indexPath)"
            cell.bottomLabel.text = "Line 1\nLine 2\nLine 3\nLine 4"
    
            // init to "collapsed"
            // in actual use, this would be tracked so the row would remain expanded or collapsed
            // on reuse (when the table is scrolled)
            cell.shimHeightConstraint.constant = 0
    
            if true {
                cell.topLabel.backgroundColor = .clear
                cell.theButton.backgroundColor = .clear
                cell.bottomLabel.backgroundColor = .clear
                cell.theShim.backgroundColor = .clear
            }
    
            cell.myCallBack = {
                UIView.animate(withDuration: 0.3) { // It must be 0.3
                    self.tableView.beginUpdates()
                    cell.shimHeightConstraint.constant = (cell.shimHeightConstraint.constant == 0) ? cell.bottomLabel.frame.size.height : 0
                    self.tableView.layoutIfNeeded()
                    self.tableView.endUpdates()
                }
            }
    
            return cell
        }
    
    }
    

    【讨论】:

    • 我认为这种方式比我的要复杂得多...我以前尝试过这种方式。但是我必须使用stackView,因为有时单元格没有“阅读更多”和内容标签,并且stackView末尾可能还有另一个图像。 (是的,我正在编写一个 SNS 应用程序)。所以子视图是动态的。如果我将stackView的间距设置为10(不是0),使用这种方式会导致两个间距在ShimView旁边,通过ShinView是不可见的。无论如何,非常感谢您的长回答!
    猜你喜欢
    • 2021-02-10
    • 2017-08-23
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    相关资源
    最近更新 更多