Как пересчитать ограничения после поворота устройства - PullRequest
0 голосов
/ 02 апреля 2019

В ячейке моего табличного представления есть представление стека, которое содержит представления. У меня есть конечные ограничения для просмотра стека. Я вычисляю значение этих конечных ограничений на основе того, сколько представлений я должен показать в представлении стека.

Есть ли способ, которым мы можем пересчитать это значение конечного ограничения и отобразить представление без перезагрузки табличного представления в 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

Ответы [ 2 ]

1 голос
/ 02 апреля 2019

Есть несколько способов сделать это - пересчитать размер при вращении (или изменении размера) вероятно не лучший способ.

Одним из подходов, использующих преимущества UIStackView для обработки всего макета, будет добавление «пустых» представлений в ваше представление стека. Если вы устанавливаете для отображения только 1 или 2 «реальных» представлений, вы также можете отобразить «пустые» представления для заполнить 3 «столбцы».

Итак, предполагая, что вы можете показать строку с реальными представлениями Zero, оставьте свой прототип как есть, но тогда:

  • добавить ссылку на IBOutlet в представление стека
  • в awakeFromNib(), создайте и добавьте 3 очистки UIView s в представление стека
  • отслеживать реальные представления и пустые представления в массивах

Теперь, когда вы устанавливаете, какие представления показывать, скрыть представления (ей) не показывать и показывать достаточно пустых представлений, чтобы сохранить 3 вида видимыми.

Примеры:

  • [1, 2] скрыть view3 и показать blank1
  • [2] скрыть view1 и view3 и показать blank1 и blank2

Таким образом, у вас всегда будет 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
    }

}

В результате получается портрет:

image

and Landscape:

image


Edit:

Вот еще один пример, использующий массив структур со свойствами .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 голосов
/ 02 апреля 2019

Вам следует реализовать метод

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

, который вызывается при переходе устройства в новый вид (альбомная или книжная).В этом вы можете изменить свое ограничение и вызвать

view.setNeedsLayout() Чтобы отметить, что раскладка должна быть пересчитана в следующем Runloop.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...