如何在设备旋转后重新计算约束

问题描述 投票:0回答:2

在我的表视图的单元格中,我堆叠了包含视图的视图。我跟踪堆栈视图的约束。我根据我在堆栈视图中显示的视图数来计算此尾随约束的值。

有没有什么办法可以重新计算这个尾随约束值并显示视图而无需在设备旋转后重新加载viewWillTransition中的表视图?

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    self.tableView.reloadData()

    // self.view.layoutIfNeeded() // This doesn't recalculate constraints
}

Storyboard

layoutIfNeeded

ios swift uitableview uistackview
2个回答
1
投票

有几种方法可以做到这一点 - 重新计算旋转尺寸(或尺寸变化)可能不是最好的方法。

利用UIStackView处理所有布局的一种方法是在堆栈视图中添加“空白”视图。如果您只设置1或2个“真实”视图,则可以显示“空白”视图以填写3“列。”

因此,假设您可能显示具有零实际视图的行,请保持原型不变,但随后:

  • 将IBOutlet引用添加到堆栈视图
  • awakeFromNib()中,创建并添加3个清晰的UIViews到堆栈视图
  • 跟踪数组中的真实视图和空白视图

现在,当您设置要显示的视图时,隐藏不显示的视图并显示足够的空白视图以保持3个视图可见。

例子:

  • [1, 2]隐藏view3并展示blank1
  • [2]隐藏view1view3并显示blank1blank2

因此,您的堆栈中将始终有3个子视图,并且不需要进行任何计算...自动布局将保持它们的排列。

这是一个示例实现:

class ThreeColCell: UITableViewCell {

    @IBOutlet var mainStackView: UIStackView!

    @IBOutlet var view1: UIView!
    @IBOutlet var view2: UIView!
    @IBOutlet var view3: UIView!

    var arrayOfRealViews: [UIView] = [UIView]()
    var arrayOfBlankViews: [UIView] = [UIView]()

    var myData: [Int] = [Int]() {
        didSet {
            // hide all the views in the stack
            mainStackView.arrangedSubviews.forEach {
                $0.isHidden = true
            }

            // show the specified "real" views
            myData.forEach { i in
                arrayOfRealViews[i - 1].isHidden = false
            }

            // if fewer than 3 "real" views, show "blank" view(s)
            for i in 0..<(3 - myData.count) {
                arrayOfBlankViews[i].isHidden = false
            }
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        commonInit()
    }

    func commonInit() -> Void {
        // ordered array of views 1 to 3
        arrayOfRealViews = [view1, view2, view3]

        // add 3 "blank" views to the stack view
        //  and to array of blank views
        for _ in 0..<3 {
            let v = UIView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.backgroundColor = .clear
            mainStackView.addArrangedSubview(v)
            arrayOfBlankViews.append(v)
        }
    }

}

class ThreeColTableViewController: UITableViewController {

    var theData = [
        [1, 2],
        [1, 2, 3],
        [1],
        [1, 2, 3],
        [2],
        [2, 3],
        [1, 2, 3],
        [3],
        [2, 3],
        [1, 2, 3],
    ]


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ThreeColCell", for: indexPath) as! ThreeColCell
        cell.myData = theData[indexPath.row]
        return cell
    }

}

导致肖像:

和景观:


编辑:

这是另一个例子,使用带有.isDisabled1(和2和3)属性的结构数组:

struct Profile {

    var isDisabled1 = false
    var isDisabled2 = false
    var isDisabled3 = false

}

class ThreeColCell: UITableViewCell {

    @IBOutlet var mainStackView: UIStackView!

    @IBOutlet var view1: UIView!
    @IBOutlet var view2: UIView!
    @IBOutlet var view3: UIView!

    var arrayOfRealViews: [UIView] = [UIView]()
    var arrayOfBlankViews: [UIView] = [UIView]()

    var myProfile: Profile = Profile() {
        didSet {
            // hide all the views in the stack
            mainStackView.arrangedSubviews.forEach {
                $0.isHidden = true
            }

            // I don't know how you have your button/label views set up, but here
            // you would set button titles and label texts based on myProfile properties

            // create a [1, 2, 3] array based on the .isDisabled# properties of the Profile object
            var a = [Int]()

            if !myProfile.isDisabled1 {
                a.append(1)
            }
            if !myProfile.isDisabled2 {
                a.append(2)
            }
            if !myProfile.isDisabled3 {
                a.append(3)
            }

            // you now have an array "a" that will be
            //  [1, 2, 3]    or
            //  [1, 2]       or
            //  [2]          or
            //  [2, 3]       etc

            // show the specified "real" views (arrays are Zero-based)
            a.forEach { i in
                arrayOfRealViews[i - 1].isHidden = false
            }

            // pad stackview to 3 using "blank" view(s)
            // if 1 real view, show 2 blank views
            // if 2 real views, show 1 blank view
            // if 3 real views, don't show any blank views
            for i in 0..<(3 - a.count) {
                arrayOfBlankViews[i].isHidden = false
            }

        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        // ordered array of views 1 to 3
        arrayOfRealViews = [view1, view2, view3]

        // add 3 "blank" views to the stack view
        //  and to array of blank views
        for _ in 0..<3 {
            let v = UIView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.backgroundColor = .clear
            mainStackView.addArrangedSubview(v)
            arrayOfBlankViews.append(v)
        }
    }

}

class ThreeColTableViewController: UITableViewController {

    var profilesArray: [Profile] = [Profile]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // create a few Profiles
        // all 3 views are "enabled" by default

        var p = Profile()

        profilesArray.append(p)

        // Profile with views 2 and 3 disabled
        p = Profile()
        p.isDisabled2 = true
        p.isDisabled3 = true

        profilesArray.append(p)

        // Profile with view 3 disabled
        p = Profile()
        p.isDisabled3 = true

        profilesArray.append(p)

        // Profile with view 1 disabled
        p = Profile()
        p.isDisabled1 = true

        profilesArray.append(p)

        // Profile with views 1 and 2 disabled
        p = Profile()
        p.isDisabled1 = true
        p.isDisabled2 = true

        profilesArray.append(p)

    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ThreeColCell", for: indexPath) as! ThreeColCell

        cell.myProfile = profilesArray[indexPath.row]

        return cell
    }

}

0
投票

您应该实现该方法

func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)

当设备转换到新视图(横向或纵向)时会调用它。在此,您可以更改约束和调用

view.setNeedsLayout()标记需要在下一个Runloop中重新计算布局。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.