UIStackView настройка layoutMargins в выравнивании разрывов кода - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь добавить layoutMargins к некоторым элементам в UIStackView, который я создаю в коде. Я пробовал то же самое в IB, и оно отлично работает, но когда я добавляю layoutMargins и я устанавливаю isLayoutMarginsRelativeArrangement = true, тогда выравнивание моего стекового представления нарушается.

Код моего стекового представления следующий:

@objc lazy var buttonsStackView: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [doneButton, separatorView, giftButton])
        stack.layoutMargins = UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 4)
        stack.isLayoutMarginsRelativeArrangement = true
        stack.axis = .horizontal
        stack.frame = CGRect(x: 0, y: 0, width: 150, height: 44)
        stack.spacing = 4
        stack.distribution = .equalCentering
        stack.alignment = .center

        let bgView = UIView(frame: stack.bounds)
        stackViewBackground = bgView
        bgView.backgroundColor = ColorManager.shared.grayColor
        bgView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        stack.insertSubview(bgView, at: 0)

        separatorView.heightAnchor.constraint(equalTo: stack.heightAnchor, multiplier: 0.8).isActive = true

        return stack
    }()

SeparatorView имеет ограничение ширины всего лишь 1pt, в то время как две кнопки оставлены без ограничений для сохранения их intrinsicContentSize.

Вот как выглядит мой stackView, когда isLayoutMarginsRelativeArrangement равен false : enter image description here

Но очевидно, что необходимы левое и правое поля, поэтому при установке isLayoutMarginsRelativeArrangement на true разрывы выравнивания моего стека: enter image description here

К сожалению, я не могу использовать IB для этого конкретного представления, и мне нужно инициализировать его из кода. Любая идея о том, как это исправить, очень ценится. Спасибо!

1 Ответ

0 голосов
/ 07 мая 2020

Вот пример создания этого пользовательского вида с separator по центру по горизонтали и кнопками по центру на каждой "стороне":

protocol DoneGiftDelegate: class {
    func doneButtonTapped()
    func giftButtonTapped()
}

class DoneGiftView: UIView {

    weak var delegate: DoneGiftDelegate?

    let doneButton: UIButton = {
        let v = UIButton(type: .system)
        v.setTitle("Done", for: [])
        v.tintColor = .white
        return v
    }()

    let giftButton: UIButton = {
        let v = UIButton(type: .system)
        v.setImage(UIImage(systemName: "gift.fill"), for: [])
        v.tintColor = .white
        return v
    }()

    let separatorView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    func commonInit() -> Void {

        backgroundColor = .lightGray // ColorManager.shared.grayColor

        [doneButton, separatorView, giftButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        // width and height constraints: 150 x 44
        //  set Priority to 999 so it can be overriden by controller if desired
        let widthConstraint = widthAnchor.constraint(equalToConstant: 150.0)
        widthConstraint.priority = UILayoutPriority(rawValue: 999)
        let heightConstraint = heightAnchor.constraint(equalToConstant: 44.0)
        heightConstraint.priority = UILayoutPriority(rawValue: 999)

        NSLayoutConstraint.activate([

            // doneButton Leading to Leading
            doneButton.leadingAnchor.constraint(equalTo: leadingAnchor),
            // separator Leading to doneButton Trailing
            separatorView.leadingAnchor.constraint(equalTo: doneButton.trailingAnchor),
            // giftButton Leading to separator Trailing
            giftButton.leadingAnchor.constraint(equalTo: separatorView.trailingAnchor),
            // giftButton Trailing to Trailing
            giftButton.trailingAnchor.constraint(equalTo: trailingAnchor),

            // all centered vertically
            doneButton.centerYAnchor.constraint(equalTo: centerYAnchor),
            separatorView.centerYAnchor.constraint(equalTo: centerYAnchor),
            giftButton.centerYAnchor.constraint(equalTo: centerYAnchor),

            // doneButton Height = Height
            doneButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1.0),
            // separator Height = 80% of Height
            separatorView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.8),
            // giftButton Height = Height
            giftButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1.0),

            // separator Width = 1
            separatorView.widthAnchor.constraint(equalToConstant: 1.0),

            // doneButton Width = giftButton Width
            doneButton.widthAnchor.constraint(equalTo: giftButton.widthAnchor, multiplier: 1.0),

            // self Width and Height
            widthConstraint,
            heightConstraint,
        ])

        // add target actions for buttons
        doneButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        giftButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)

    }

    @objc func buttonTapped(_ sender: UIButton) -> Void {
        if sender == doneButton {
            delegate?.doneButtonTapped()
        } else {
            delegate?.giftButtonTapped()
        }
    }

}

class DemoViewController: UIViewController, DoneGiftDelegate {

    let doneGiftView: DoneGiftView = DoneGiftView()

    let testView: UIView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        doneGiftView.translatesAutoresizingMaskIntoConstraints = false
        testView.translatesAutoresizingMaskIntoConstraints = false

        testView.addSubview(doneGiftView)
        view.addSubview(testView)

        // so we can see the view frame
        testView.backgroundColor = .cyan

        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([

            // testView Top: 100
            //  Leading / Trailing with 20-pts "padding"
            //  Height: 80
            testView.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
            testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            testView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            testView.heightAnchor.constraint(equalToConstant: 80.0),

            // doneGiftView Trailing to testView Trailing
            doneGiftView.trailingAnchor.constraint(equalTo: testView.trailingAnchor),
            // doneGiftView centered vertically in testView
            doneGiftView.centerYAnchor.constraint(equalTo: testView.centerYAnchor),

        ])

        doneGiftView.delegate = self
    }

    func doneButtonTapped() {
        print("Done button tapped!")
        // do what we want when Done button tapped
    }
    func giftButtonTapped() {
        print("Gift button tapped")
        // do what we want when Gift button tapped
    }
}

Пример результата:

enter image description here

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