Как обновить ограничение высоты с помощью SnapKit и обновить высоту ячейки? - PullRequest
0 голосов
/ 26 октября 2018

У меня есть TableViewCell и две кнопки для переключения различных ограничений.
Я хочу обновить ограничение по высоте и высоте ячейки.
как следующий pic1
когда я нажимаю кнопку B, вид меняется как pic2
Затем я нажимаю кнопку A, вид изменится на pic1
Я пытаюсь изменить ограничения, но мне не удается обновить высоту.
Есть идеи или ответ мне?
Спасибо

pic1

enter image description here

pic2

enter image description here

Вот код:

class CellContainView: UIView {

let buttonA: UIButton = { () -> UIButton in
    let ui = UIButton()
    ui.titleLabel?.numberOfLines = 0
    ui.setTitle("Click\nA", for: .normal)
    ui.backgroundColor = UIColor.blue
    return ui
}()

let buttonB: UIButton = { () -> UIButton in
    let ui = UIButton()
    ui.titleLabel?.numberOfLines = 0
    ui.setTitle("Click\nB", for: .normal)
    ui.backgroundColor = UIColor.gray
    return ui
}()

let buttonC: UIButton = { () -> UIButton in
    let ui = UIButton()
    ui.titleLabel?.numberOfLines = 0
    ui.setTitle("Click\nC", for: .normal)
    ui.backgroundColor = UIColor.brown
    return ui
}()

let labelA: UILabel = { () -> UILabel in
    let ui = UILabel()
    ui.text = "Test"
    return ui
}()

let viewA: UIView = { () -> UIView in
    let ui = UIView()
    ui.backgroundColor = UIColor.red
    return ui
}()

override init(frame: CGRect) {
    super.init(frame: frame)

    addUI()
    addConstrain()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func addUI() {

    self.addSubview(buttonA)
    self.addSubview(buttonB)
    self.addSubview(buttonC)
    self.addSubview(labelA)
    self.addSubview(viewA)

}

func addConstrain() {

    buttonA.snp.makeConstraints { (make) in
        make.left.top.equalToSuperview()
        make.height.equalTo(60)
    }

    buttonB.snp.makeConstraints { (make) in
        make.left.equalTo(buttonA.snp.right)
        make.top.right.equalToSuperview()
        make.width.equalTo(buttonA.snp.width)
        make.height.equalTo(buttonA.snp.height)
    }

    buttonC.snp.makeConstraints { (make) in
        make.left.equalTo(15)
        make.right.equalTo(-15)
        make.bottom.equalTo(-15)
        make.height.equalTo(50)
    }

    labelA.snp.makeConstraints { (make) in
        make.left.equalTo(15)
        make.top.equalTo(buttonA.snp.bottom).offset(15)
        make.width.equalTo(195)
        make.height.equalTo(50)
    }

    viewA.snp.makeConstraints { (make) in
        make.left.equalTo(labelA.snp.right)
        make.top.equalTo(buttonA.snp.bottom).offset(15)
        make.right.equalTo(-15)
        make.height.equalTo(50)
        make.bottom.equalTo(buttonC.snp.top).offset(-10)
    }
}

func updateConstrain(sender: UIButton) {

    switch sender {
    case buttonA:

        viewA.snp.updateConstraints { (make) in
            make.height.equalTo(50)
        }

    case buttonB:

        viewA.snp.updateConstraints { (make) in
            make.height.equalTo(150)
        }

    default:
        break
    }

}

}


class TestTableViewCell: UITableViewCell {

let cellContainView: CellContainView = { () -> CellContainView in
    let ui = CellContainView()
    ui.backgroundColor = UIColor.orange
    return ui
}()

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    self.addSubview(cellContainView)

    cellContainView.snp.makeConstraints { (make) in
        make.left.top.equalTo(15)
        make.bottom.right.equalTo(-15)
    }

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let tableView: UITableView = { () -> UITableView in
    let ui = UITableView()
    return ui
}()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.delegate = self
    tableView.dataSource = self
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44
    tableView.register(TestTableViewCell.self, forCellReuseIdentifier: "TestTableViewCell")
    tableView.tableFooterView = UIView()

    self.view.addSubview(tableView)
    tableView.snp.makeConstraints { (make) in
        make.top.left.right.bottom.equalToSuperview()
    }
}

@objc func buttonAClicked(sender: UIButton) {

    let index = IndexPath(row: 0, section: 0)
    let cell = tableView.cellForRow(at: index) as! TestTableViewCell
    cell.cellContainView.updateConstrain(sender: sender)
    tableview.reloadData()
}

@objc func buttonBClicked(sender: UIButton) {

    let index = IndexPath(row: 0, section: 0)
    let cell = tableView.cellForRow(at: index) as! TestTableViewCell
    cell.cellContainView.updateConstrain(sender: sender)
    tableview.reloadData()
}

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

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableViewCell", for: indexPath) as! TestTableViewCell

    cell.cellContainView.buttonA.addTarget(self, action: #selector(buttonAClicked), for: .touchUpInside)
    cell.cellContainView.buttonB.addTarget(self, action: #selector(buttonBClicked), for: .touchUpInside)

    return cell
}

}

Обновление проблемы ограничения при нажатии кнопки B (добавить представление обновленияA heightConstrain & tableview.reloadData ()):

TestCellUpdateHeight[29975:5195310] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(
"<SnapKit.LayoutConstraint:0x6040000a4320@CellContainView.swift#75 UIButton:0x7fa1d0d0d680.height == 60.0>",
"<SnapKit.LayoutConstraint:0x6040000a49e0@CellContainView.swift#89 UIButton:0x7fa1d0d10610.height == 50.0>",
"<SnapKit.LayoutConstraint:0x6040000a51c0@CellContainView.swift#104 UIView:0x7fa1d0d11130.height == 150.0>",
"<SnapKit.LayoutConstraint:0x6040000a4800@CellContainView.swift#80 UIButton:0x7fa1d0d0f7b0.top == TestCellUpdateHeight.CellContainView:0x7fa1d0d0d470.top>",
"<SnapKit.LayoutConstraint:0x6040000a4a40@CellContainView.swift#82 UIButton:0x7fa1d0d0f7b0.height == UIButton:0x7fa1d0d0d680.height>",
"<SnapKit.LayoutConstraint:0x6040000a4ec0@CellContainView.swift#88 UIButton:0x7fa1d0d10610.bottom == TestCellUpdateHeight.CellContainView:0x7fa1d0d0d470.bottom - 15.0>",
"<SnapKit.LayoutConstraint:0x6040000a5100@CellContainView.swift#102 UIView:0x7fa1d0d11130.top == UIButton:0x7fa1d0d0f7b0.bottom + 15.0>",
"<SnapKit.LayoutConstraint:0x6040000a5220@CellContainView.swift#105 UIView:0x7fa1d0d11130.bottom == UIButton:0x7fa1d0d10610.top - 10.0>",
"<SnapKit.LayoutConstraint:0x6040000a52e0@TestTableViewCell.swift#26 TestCellUpdateHeight.CellContainView:0x7fa1d0d0d470.top == TestCellUpdateHeight.TestTableViewCell:0x7fa1d208a000.top + 15.0>",
"<SnapKit.LayoutConstraint:0x6040000a53a0@TestTableViewCell.swift#27 TestCellUpdateHeight.CellContainView:0x7fa1d0d0d470.bottom == TestCellUpdateHeight.TestTableViewCell:0x7fa1d208a000.bottom - 15.0>",
"<NSLayoutConstraint:0x6080002819f0 'UIView-Encapsulated-Layout-Height' TestCellUpdateHeight.TestTableViewCell:0x7fa1d208a000'TestTableViewCell'.height == 230   (active)>"
)

Will attempt to recover by breaking constraint 

Ответы [ 4 ]

0 голосов
/ 26 октября 2018

Я думаю, что вам не нужно изменять Bottom Constraint. То, что вам нужно, это применить ограничение высоты к redView.и изменить его в соответствии с вашей кнопкой Selection.

func updateConstrain(sender: UIButton) {

    switch sender {
    case buttonA:

        redView.snp.updateConstraints { (make) in
            make.heigh.equalTo(10)
        }

    case buttonB:

        redView.snp.updateConstraints { (make) in
             make.heigh.equalTo(100)
        }

    default:
        break
    }

}
}

И не забудьте перезагрузить Specific Row после обновления Constraint

@objc func buttonAClicked(sender: UIButton) {

    let index = IndexPath(row: 0, section: 0)
    let cell = tableView.cellForRow(at: index) as! TestTableViewCell
    cell.cellContainView.updateConstrain(sender: sender)
    yourtableview.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.none)


}

@objc func buttonBClicked(sender: UIButton) {

    let index = IndexPath(row: 0, section: 0)
    let cell = tableView.cellForRow(at: index) as! TestTableViewCell
    cell.cellContainView.updateConstrain(sender: sender)
 yourtableview.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.none)
}
0 голосов
/ 26 октября 2018

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

Таблица может обновлять высоту своих ячеек только в результате вызова reloadData(), после чего она запросит у delegate высоту ячейки(или рассчитать автоматически, если ваши ячейки имеют собственный размер).

Итак, чтобы получить желаемый эффект, вы можете сделать что-то вроде следующего.

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

В методе делегата таблицы tableView(_:, heightForRowAt:) возвращает правильную высоту для ячейки.

Это не идеально, и служит просто направлением для рассмотренияваше решение.Моя главная мысль - вам нужно перезагрузить табличное представление, чтобы изменить высоту ячейки.

0 голосов
/ 26 октября 2018

Если вам нужно пересчитать ячейку высоты (без воссоздания ячеек / перезагрузки ячеек), просто наберите:

tableView.beginUpdates()
tableView.endUpdates()
0 голосов
/ 26 октября 2018

Что вы сейчас делаете

labelA.snp.updateConstraints { (make) in
   make.bottom.equalTo(buttonC.snp.top).offset(-100)
}

увеличит нижнее расстояние метки A, но оставит ее верхнюю константу такой же, как вам нужно либо

1 - обновить высоту labelA

или

2 - обновить высоту redView перед ним

Также не забудьте позвонить

cell.cellContainView.updateConstrain(sender: sender)
cell.layoutIfNeeded()

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

Вы также можете сделать это

func tableView(_ tableView: UITableView, 
     heightForRowAt indexPath: IndexPath) -> CGFloat
   return expandArr[indexPath.row] ? 300 : 100
}

, где

var expandArr = [Bool]()

указывает, расширяется ли ячейка или нет, также, если у вас есть модель, вы можете добавить к ней значение bool вместо этого отдельного arr (это для иллюстрации)

...