Swift 3 – Пользовательский радиус UIButton удаляет ограничения?

Мой контроллер представления имеет представление стека с 3 кнопками. Одна фиксирована в центре с фиксированной шириной и стеком, настроенным на пропорциональное заполнение, так что две другие кнопки будут симметричными.

Однако я также настраиваю угловой радиус кнопок, и как только приложение загружает размер кнопки, размер кнопки изменяется нежелательным образом.

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

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

Попытка кодирования скруглить нужные углы:

@IBOutlet fileprivate weak var button: UIButton! { didSet {
    button.round(corners: [.topRight, .bottomLeft], radius: 50 , borderColor: UIColor.blue, borderWidth: 5.0)
    button.setNeedsUpdateConstraints()
    button.setNeedsLayout()
} }

override func viewDidLayoutSubviews() {
   button.layoutIfNeeded()
}

ovverride func updateViewContraints() {
    button.updateConstraintsIfNeeded()
    super.updateViewConstraints()
}

Используемое расширение UIView можно найти здесь: https://stackoverflow.com/a/35621736/5434541

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


person lifewithelliott    schedule 17.01.2017    source источник
comment
Вы получаете одинаковое поведение с обоими методами?   -  person Ben    schedule 19.01.2017
comment
@Ben Да, я получаю такое же поведение со всеми попытками. В настоящее время это происходит в симуляторе, протестированном на iPhone 5, кажется, он работает так, как мне бы хотелось, но неожиданное поведение чего-то подобного заставляет меня беспокоиться, не зная, может ли это произойти на других устройствах. Также, как только я реализовал эти методы, приложение в настоящее время сильно отстает! Я знаю, что это не имеет отношения к конкретному вопросу, но мне любопытно, должны ли подпредставления viewDidlayout выполняться в другом потоке? Спасибо!   -  person lifewithelliott    schedule 19.01.2017


Ответы (1)


Не видя вашего полного кода, я подозреваю, что вы получаете это, потому что он рисует несколько слоев с рамкой и никогда не удаляет их! Если размер кнопок изменяется, старые слои остаются. Вот фрагмент, показывающий удаление старого слоя при перерисовке, который вы сможете адаптировать. Я протестировал это в представлении стека, и оно также корректно ведет себя при вращении:

class RoundedCorner: UIButton {

    var lastBorderLayer:CAShapeLayer?
    override func layoutSubviews() { setup() }

    func setup() {
        let r = self.bounds.size.height / 2
        let path = UIBezierPath(roundedRect: self.bounds,
                                byRoundingCorners: [.topLeft, .bottomRight],
                                cornerRadii: CGSize(width: r, height: r))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        addBorder(mask: mask, borderColor: UIColor.blue, borderWidth: 5)
        self.layer.mask = mask
    }

    func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
        let borderLayer = CAShapeLayer()
        borderLayer.path = mask.path
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.lineWidth = borderWidth
        borderLayer.frame = bounds
        if let last = self.lastBorderLayer, let index = layer.sublayers?.index(of: last) {
            layer.sublayers?.remove(at: index)
        }
        layer.addSublayer(borderLayer)
        self.lastBorderLayer = borderLayer
    }
}

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

person Ben    schedule 19.01.2017
comment
Итак, я собирался реализовать ваш класс RoundedCorner, но после прочтения вашего кода я почувствовал, что, возможно, я делал что-то не так с моей стороны в исходном вопросе. Поэтому я попытался изучить немного больше и отредактировал вопрос выше, чтобы обновить результаты. Я очень ценю помощь, так как ваш ответ ведет меня в правильном направлении. - person lifewithelliott; 19.01.2017
comment
Не знаете, что вы редактировали, можете ли вы поделиться всем классом кнопок? - person Ben; 20.01.2017
comment
кнопка - это просто кнопка раскадровки, подключенная к контроллеру представления. Для него не создается пользовательская кнопка подкласса. Приложение запускается, и как только кнопка установлена, didSet вызывает вызов метода round() , а затем следующие методы setNeeds() сообщают контроллеру об обновлении макета при вызове viewDidUpdateLayoutSubviews(). Я верю, что так оно и есть. - person lifewithelliott; 20.01.2017
comment
Этот метод по-прежнему будет иметь исходную проблему, на которую я указал. Каждый раз, когда кнопка перерисовывается, вы добавляете еще один подслой. Сначала вы должны очистить старый слой (как в моем примере с layer.sublayers?.remove). Вот почему вы видите несколько закругленных углов. - person Ben; 20.01.2017