Как установить backgroundColor UISegmentedControl на белый в iOS 13

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

Я видел вопросы, которые отвечают, как установить selectedSegmentTintColor и тому подобное, но я изо всех сил пытаюсь настроить backgroundColor, чтобы он говорил .white, независимо от того, что я делаю, он всегда отображается немного серым, даже если не применяется tintColor или аналогичный параметр . Установка backgroundColor на другие цвета показывает такое же поведение, но наиболее очевидно с белым. Загадки усугубляет то, что, хотя эта разница проявляется как на симуляторах iOS 13, так и на физическом устройстве под управлением iOS 13, визуальный отладчик (в XCode 11 GM2) не показывает этой разницы!

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

Устройство под управлением iOS 13 (белый backgroundColor)  введите описание изображения здесь

То же представление / код, что и в Visual Debugger (белый backgroundColor)  введите описание изображения здесь

Устройство под управлением iOS 13 (синий цвет фона)  введите описание изображения здесь

Я пробовал применить backgroundImage, как предложено в этом сообщении SO: UISegmentedControl iOS 13 clear color, но это приводит к тому, что стиль возвращается к тому, как он выглядел в iOS 12, и вы также теряете красивую анимацию.

Любые рекомендации или предложения приветствуются! Я также отправил отчет об ошибке в Apple, посмотрю, получится ли из этого что-нибудь.


person Phil    schedule 25.09.2019    source источник
comment
Вы решили эту проблему? Я получаю то же самое   -  person Carioni    schedule 24.11.2019
comment
К сожалению, нет. Я открыл отчет об ошибке в Apple через пару дней после публикации этого вопроса, но, к сожалению, до сих пор не получил никакого ответа.   -  person Phil    schedule 25.11.2019
comment
проверьте мой ответ ниже, я решил проблему таким образом   -  person Carioni    schedule 03.12.2019


Ответы (4)


У меня такая же проблема, и нет крутого способа ее решить. Итак, я сделал это небольшое обходное решение. Мне это не нравится и я не горжусь этим, но это работает.

func fixBackgroundSegmentControl( _ segmentControl: UISegmentedControl){
    if #available(iOS 13.0, *) {
        //just to be sure it is full loaded
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { 
            for i in 0...(segmentControl.numberOfSegments-1)  {
                let backgroundSegmentView = segmentControl.subviews[i]
                //it is not enogh changing the background color. It has some kind of shadow layer 
                backgroundSegmentView.isHidden = true 
            }
        }
    }
}
person Erick Silva    schedule 28.11.2019
comment
Посмотрите на мой ответ ниже, я только что нашел способ сделать это немного круче, чем этот, даже если по-вашему это работает - person Carioni; 28.11.2019
comment
Это сработало! Я полностью отказался от этого, спасибо, что поделились своим решением. Это немного взломано, но, учитывая нелепость ситуации, кажется уместным :) - person Phil; 03.12.2019
comment
С этим кодом мой сегментированный элемент управления теряет текст, но серый оверлей все еще присутствует. - person IvanPavliuk; 06.02.2020
comment
Используя это решение, разделители между сегментами исчезают в моем сегментированном элементе управления. У вас такой же побочный эффект? Если нет, можете ли вы поделиться своей конфигурацией сегментированного элемента управления? - person ste8; 10.05.2020
comment
это решение не подходит для меня, в то же время исчезает титр: / - person Ahmed Mh; 03.07.2020
comment
Этот трюк работает также с использованием обычного DispatchQueue.main.async(execute:) вместо 0,1-секундной задержки с использованием DispatchQueue.main.asyncAfter(deadline:execute:). - person alobaili; 10.08.2020

SWIFT 3 и 4+

Из этого ответа https://stackoverflow.com/a/31652184/3249196, если вам нужен полностью белый фон без серый оверлей просто замените tintColor и backgroundColor на UIColor.white

extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(color: backgroundColor!), for: .normal, barMetrics: .default)
        setBackgroundImage(imageWithColor(color: tintColor!), for: .selected, barMetrics: .default)
        setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }

    // create a 1x1 image with this color
    private func imageWithColor(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0.0, y: 0.0, width:  1.0, height: 1.0)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor);
        context!.fill(rect);
        let image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image!
    }
}
person Carioni    schedule 28.11.2019
comment
Привет, Кариони, я действительно пробовал этот метод раньше, и если я что-то не упускаю, вы теряете анимацию при изменении выделения, что я пытаюсь сохранить. Предложение Эрика Сильвы, хотя и немного хакерское, помогает. - person Phil; 03.12.2019
comment
@Phil, можешь ли ты поделиться видео примером этого? Я не понимаю, о чем вы, потому что я не теряю анимацию - person Carioni; 04.12.2019

У меня работает (Swift 5).

let background = myColors.background
let selectedColor = myColors.foreground

if #available(iOS 13.0, *)
{
    segmentedControl.tintColor = background
    segmentedControl.backgroundColor = background
    segmentedControl.selectedSegmentTintColor = selectedColor
    segmentedControl.setTitleTextAttributes([.foregroundColor: selectedColor as Any], for: .normal)
    segmentedControl.setTitleTextAttributes([.foregroundColor: background as Any], for: .selected)
}
else
{
    segmentedControl.tintColor = background
    segmentedControl.backgroundColor = selectedColor
    segmentedControl.layer.cornerRadius = 4
}
person IvanPavliuk    schedule 06.02.2020
comment
Похоже, это работает для всех backgroundColor, кроме .white и .clear. Когда вы устанавливаете его на любой из этих двух цветов, отображается уродливый серый цвет. - person c0d3p03t; 26.02.2020
comment
@ c0d3p03t Я думаю, что наложение серого видно на любом светлом цвете. Я пытаюсь использовать легкий загар, но я также вижу его с помощью UIColor.yellow. - person arlomedia; 20.03.2021

В Xamarin.iOS это сработало для меня:

class MySegmentedControl : UISegmentedControl
{
    int insertedIndex = 0;

    public override void InsertSubview(UIView view, nint atIndex)
    {
        base.InsertSubview(view, atIndex);

        if (insertedIndex == 2 || insertedIndex == 3)
            view.Hidden = true;

        insertedIndex++;
    }
}
person bart    schedule 06.03.2020