Настраиваемая нижняя панель находится в неправильном положении для настраиваемого сегментированного элемента управления

Я пытаюсь создать пользовательский UISegmentedControl с полосой внизу под выбранным параметром. Я добавил CALayer в качестве бара. После изменения выбранной опции полоса не перемещается в ожидаемое положение.

Код для пользовательского UISegmentedControl выглядит следующим образом:

class ProfileSegmentedControl: UISegmentedControl {
    private lazy var bottomBar = getBottomBar()

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
}

private extension ProfileSegmentedControl {
    func setup() {
        tintColor = .clear
        let normalAttributes: [NSAttributedString.Key: Any] = [
            .foregroundColor: UIColor.white,
            .font: UIFont.systemFont(ofSize: 16, weight: .medium)
        ]
        setTitleTextAttributes(normalAttributes, for: .normal)
        setTitleTextAttributes([.foregroundColor: UIColor(named: "black") as Any], for: .selected)
    }
}

private extension ProfileSegmentedControl {
    func getBottomBar() -> CALayer {
        let bar = CALayer()
        bar.backgroundColor = UIColor(named: "black")?.cgColor
        layer.addSublayer(bar)
        return bar
    }

    func setBarFrame() {
        let barWidth = bounds.width / CGFloat(numberOfSegments)
        let barHeight: CGFloat = 2
        let x = barWidth * CGFloat(selectedSegmentIndex)
        let y = bounds.height - barHeight

        bottomBar.frame = CGRect(x: x, y: y, width: barWidth, height: barHeight)
    }
}

extension ProfileSegmentedControl {
    override func layoutIfNeeded() {
        super.layoutIfNeeded()
        setBarFrame()
    }
}

Требуется 2 нажатия на опцию, чтобы переместить нижнюю панель в ожидаемое положение.

Кто-нибудь может указать, почему это происходит? Кто-нибудь может указать, как это исправить?

Правка - когда представление загружается в первый раз и нажимается «Сегмент 0», полоса отображается в правильном положении, как показано ниже -

введите здесь описание изображения

При однократном нажатии на «Сегмент 1» полоса не перемещается, как показано ниже -

введите здесь описание изображения

При повторном нажатии на «Сегмент 1» полоса перемещается в правильное положение, как показано ниже:

введите здесь описание изображения


person Community    schedule 05.08.2019    source источник
comment
Обновить вопрос с изображением   -  person steveSarsawa    schedule 05.08.2019
comment
куда вы называете переезд бара?   -  person Alexandr Kolesnik    schedule 05.08.2019
comment
Рамка нижней панели задается в методе setBarFrame. Этот метод вызывается в методе layoutIfNeeded.   -  person    schedule 05.08.2019


Ответы (1)


Я не думаю, что этот подход сработает, потому что selectedSegmentIndex еще не установлен при вызове layoutIfNeeded(). Вот почему вы получаете подчеркнутый сегмент 2 при нажатии на сегмент 1 и наоборот.

Я бы предложил заменить ваше переопределение layoutIfNeeded() на:

extension ProfileSegmentedControl {

    override func layoutSubviews() {
        super.layoutSubviews()
        setBarFrame()
    }

}

а затем добавляем действие valueChanged:

@IBAction func segmentChanged(_ sender: Any) {
    if let segControl = sender as? ProfileSegmentedControl {
        segControl.setNeedsLayout()
    }
}

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

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

person DonMag    schedule 05.08.2019