Цвет градиента оттенка в сегментированном управлении

Я получаю градиентное изображение этим методом

func gradient(size:CGSize,color:[UIColor]) -> UIImage?{
    //turn color into cgcolor
    let colors = color.map{$0.cgColor}
    //begin graphics context
    UIGraphicsBeginImageContextWithOptions(size, true, 0.0)
    guard let context = UIGraphicsGetCurrentContext() else {
        return nil
    }
    // From now on, the context gets ended if any return happens
    defer {UIGraphicsEndImageContext()}
    //create core graphics context
    let locations:[CGFloat] = [0.0,1.0]
    guard let gredient = CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as NSArray as CFArray, locations: locations) else {
        return nil
    }
    //draw the gradient
    context.drawLinearGradient(gredient, start: CGPoint(x:0.0,y:size.height), end: CGPoint(x:size.width,y:size.height), options: [])
    // Generate the image (the defer takes care of closing the context)
    return UIGraphicsGetImageFromCurrentImageContext()
}

Затем я устанавливаю tintColor сегментированного элемента управления на градиент:

    let gradientImage = gradient(size: listSegmentedControl.frame.size, color: [UIColor.black, UIColor.red])!
    listSegmentedControl.tintColor = UIColor(patternImage: gradientImage)

и это не работает. Однако тот же код работает для установки backgroundColor:

    let gradientImage = gradient(size: listSegmentedControl.frame.size, color: [UIColor.black, UIColor.red])!
    listSegmentedControl.backgroundColor = UIColor(patternImage: gradientImage)

У кого-нибудь есть идеи, почему? Мне действительно нужно установить градиент tintColor. Любая помощь очень ценится.

Обновлено:

В идеале я хочу, чтобы мой сегментированный элемент управления выглядел так:

Цвет градиента оттенка в сегментированном управлении

Это может помочь: stackoverflow.com/questions/34733943/…

Daniel 02.07.2018 19:18

@Dopapp спасибо! Я попробую

Lavrin Pristazh 02.07.2018 19:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
2
2 056
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это известный способ изменить цвет оттенка UISegmentedControl.

   let sortedViews = listSegmentedControl.subviews.sorted( by: { $0.frame.origin.x < $1.frame.origin.x } )

    for (index, view) in sortedViews.enumerated() {
        if index == listSegmentedControl.selectedSegmentIndex {
            view.tintColor = UIColor(patternImage: gradientImage)
        } else {
            view.tintColor = UIColor.gray //Whatever the color of non selected segment controller tab
        }
    }

Хотя это выглядит уродливым хаком, я использую его довольно давно и кажется довольно простым. Надеюсь, поможет.

Обновлено:

Это то, что тебе нужно, приятель?

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

Обновлено еще раз:

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

Заявление об ограничении ответственности:

Как упоминал мэдди в своих комментариях ниже, это взлом, и он использует недокументированный (хотя и полный общедоступный API), но очень известный способ изменения цвета оттенка UISegemntedControl, который существует с iOS 5 (вот как я помню , дай мне знать, если я ошибаюсь)

Поэтому используйте ответ с осторожностью, помня о том, что в будущих выпусках iOS Apple мощь изменит структуру подпредставлений в UISegemntedControl и может повлиять на ваш O / P. Ничего из того, что я вижу, не приведет к сбою, но может повлиять на способ отображения O / P на экране.

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

var gradientImage : UIImage! = nil

В ViewDidLoad я инициализирую gradientImage и UISegmentedControl как

override func viewDidLoad() {
        super.viewDidLoad()
        gradientImage = gradient(size: segmentControl.frame.size, color: [UIColor.black, UIColor.red])!

        //I have specified custom font need not necessarily be used
        //Font color attribute is important though, usually `UISegementedControl` title takes color from tint color, because we might need a different color for text to highlight above gradient color am using custom font colors

        let font = UIFont(name: "HelveticaNeue-Medium", size: 20)
        segmentControl.setTitleTextAttributes([NSFontAttributeName : font!, NSForegroundColorAttributeName : UIColor.blue], for: .normal)
        segmentControl.setTitleTextAttributes([NSForegroundColorAttributeName : UIColor.white], for: .selected)

        //Set the border color and border to `UISegmentedControl` and also make it round corner

        segmentControl.layer.borderColor = UIColor(patternImage: gradientImage).cgColor
        segmentControl.layer.borderWidth = 2
        segmentControl.layer.masksToBounds = true
        segmentControl.layer.cornerRadius = 10

        //In order to update the selected Segment tint and background color we need to call multiple statements every time selection changes hence I have moved it to the function and called it in viewDidLoad

        updateGradientBackground()
    }

Наконец, определение функции updateGradientBackground такое же, как и в исходном ответе.

fileprivate func updateGradientBackground() {
        let sortedViews = segmentControl.subviews.sorted( by: { $0.frame.origin.x < $1.frame.origin.x } )
        for (index, view) in sortedViews.enumerated() {
            if index == segmentControl.selectedSegmentIndex {
                //very important thing to notice here is because tint color was not honoring the `UIColor(patternImage` I rather used `backgroundColor` to create the effect and set clear color as clear color
                view.backgroundColor = UIColor(patternImage: self.gradientImage)
                view.tintColor = UIColor.clear
            } else {
                //very important thing to notice here is because tint color was not honoring the `UIColor(patternImage` I rather used `backgroundColor` to create the effect and set clear color as clear color
                view.backgroundColor = UIColor.white //Whatever the color of non selected segment controller tab
                view.tintColor = UIColor.clear
            }
        }
    }

Наконец, в IBAction UISegmentedControl просто вызовите

@IBAction func segmentControllerTapped(_ sender: UISegmentedControl) {
    self.updateGradientBackground()
}

Надеюсь это поможет

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

rmaddy 02.07.2018 20:11

@rmaddy: Согласен. Поэтому я назвал это уродливым взломом. Хак, который работает сейчас, но имеет потенциальную опасность взлома в будущем, при этом, как говорится, этот хак, похоже, работает нормально с iOS5-6 до сих пор. Ничего не говоря в защиту своего ответа :)

Sandeep Bhandari 02.07.2018 20:30

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

Lavrin Pristazh 03.07.2018 09:29

@ lavrin-пристаж: Проверяю сейчас

Sandeep Bhandari 03.07.2018 09:46

@ lavrin-pristazh: Но чувак, предоставленный вами градиент не имеет такого же цветового эффекта, с градиентом, который вы предоставили, вы получите то, что я опубликовал выше

Sandeep Bhandari 03.07.2018 11:08

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

Lavrin Pristazh 03.07.2018 12:16

@ lavrin-pristazh: Взгляните на обновленное изображение, не беспокойтесь о квадратном углу, вы можете сделать его закругленным :)

Sandeep Bhandari 03.07.2018 12:23

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

Lavrin Pristazh 03.07.2018 12:34

@ lavrin-pristazh: дай мне минутку обновлять ответ

Sandeep Bhandari 03.07.2018 12:50

@ lavrin-pristazh: Обновил свой ответ, внимательно читайте комментарии

Sandeep Bhandari 03.07.2018 13:10

@ lavrin-pristazh: Большое спасибо, дружище :) Удачного кодирования :)

Sandeep Bhandari 03.07.2018 13:30

Я просто немного изменил ваш код и настроил сегментированный элемент управления именно так, как я хотел. Большое вам спасибо, вы спасли мне день :)

Lavrin Pristazh 03.07.2018 15:15

@ lavrin-pristazh: Рад, что смог помочь :) Удачного кодирования :)

Sandeep Bhandari 03.07.2018 16:48

Реализован цвет градиента для ручки на iOS13 + UISegmentControl. Добавлен subview с градиентом, затем установил маску для него и скопировал анимацию в соответствии с оригинальной ручкой.

// 1 - Make subclass
class GradientSegment: UISegmentedControl {
    // this could be UIImageView
    lazy var gradientView: GradientView = {
        let view = GradientView(frame: self.bounds)
        view.startColor = ...
        view.endColor = ...
        view.horizontalMode = true
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        return view
    }()

    let gradientMask = UIImageView()

    // 2 - override init
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    private func setup() {
        addSubview(gradientView)
        gradientView.mask = gradientMask
    }

    // 3 - Copy knob position and animations
    override func insertSubview(_ view: UIView, at index: Int) {
        super.insertSubview(view, at: index)
        if index == 3, let view = view as? UIImageView {
            gradientMask.image = view.image
            gradientMask.frame = view.frame

            if let keys = view.layer.animationKeys() {
                for key in keys {
                    guard let animation = view.layer.animation(forKey: key) else {
                        continue
                    }
                    gradientMask.layer.add(animation, forKey: key)
                }
            }
        }
    }
}

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

Другие вопросы по теме