Я получаю градиентное изображение этим методом
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. Любая помощь очень ценится.
Обновлено:
В идеале я хочу, чтобы мой сегментированный элемент управления выглядел так:
@Dopapp спасибо! Я попробую





Это известный способ изменить цвет оттенка 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: Согласен. Поэтому я назвал это уродливым взломом. Хак, который работает сейчас, но имеет потенциальную опасность взлома в будущем, при этом, как говорится, этот хак, похоже, работает нормально с iOS5-6 до сих пор. Ничего не говоря в защиту своего ответа :)
Спасибо за Ваш ответ! Я внедрил ваш код в свое приложение, но он не работает. Я, должно быть, делаю что-то не так ... Не могли бы вы проверить это со своей стороны и сообщить мне, работает ли это для вас?
@ lavrin-пристаж: Проверяю сейчас
@ lavrin-pristazh: Но чувак, предоставленный вами градиент не имеет такого же цветового эффекта, с градиентом, который вы предоставили, вы получите то, что я опубликовал выше
Да, извините, градиент, который я предоставил, использовался только для тестирования. Моя проблема в том, что я не могу получить эту рамку вокруг невыделенного сегмента, а углы не скруглены.
@ lavrin-pristazh: Взгляните на обновленное изображение, не беспокойтесь о квадратном углу, вы можете сделать его закругленным :)
Да, это то, что мне нужно. Если бы вы поделились своим кодом, вы бы мне очень помогли, и я приму ваш ответ
@ lavrin-pristazh: дай мне минутку обновлять ответ
@ lavrin-pristazh: Обновил свой ответ, внимательно читайте комментарии
@ lavrin-pristazh: Большое спасибо, дружище :) Удачного кодирования :)
Я просто немного изменил ваш код и настроил сегментированный элемент управления именно так, как я хотел. Большое вам спасибо, вы спасли мне день :)
@ lavrin-pristazh: Рад, что смог помочь :) Удачного кодирования :)
Реализован цвет градиента для ручки на 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)
}
}
}
}
}
Это небезопасный подход, потому что внешний вид станет недействительным, когда яблоко изменит макет элемента управления, но пока он работает.
Это может помочь: stackoverflow.com/questions/34733943/…