[英]Gradient tint color in segmented control
I get gradient image with this method我用这种方法得到渐变图像
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()
}
Then I set tintColor of segmented control to gradient:然后我将分段控件的 tintColor 设置为渐变:
let gradientImage = gradient(size: listSegmentedControl.frame.size, color: [UIColor.black, UIColor.red])!
listSegmentedControl.tintColor = UIColor(patternImage: gradientImage)
and that doesn't work.这不起作用。 However, same code works for setting backgroundColor:但是,相同的代码可用于设置 backgroundColor:
let gradientImage = gradient(size: listSegmentedControl.frame.size, color: [UIColor.black, UIColor.red])!
listSegmentedControl.backgroundColor = UIColor(patternImage: gradientImage)
Does anybody have any ideas why?有没有人知道为什么? I really need to set gradient tintColor.我真的需要设置渐变 tintColor。 Any help is very appreciated.非常感谢任何帮助。
EDIT:编辑:
Ideally I want my segmented control to look like this:理想情况下,我希望我的分段控件如下所示:
This is a known hack to change the tint color of UISegmentedControl
这是一个已知的改变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
}
}
Though looks like a ugly hack, I have been using it from a quite a while and seems fairly straight forward.虽然看起来像一个丑陋的黑客,但我已经使用它有一段时间了,而且看起来相当简单。 Hope it helps.希望能帮助到你。
EDIT:编辑:
Is this what you need buddy?这是你需要的朋友吗?
If yes lemme know, Ill post the code for the same.如果是,让我知道,我会发布相同的代码。
EDIT 2:编辑2:
As OP has mentioned in his comment that the output he is expecting is same as the one I showed in image above, providing code for the same.正如 OP 在他的评论中提到的,他期望的输出与我在上图中显示的输出相同,并提供相同的代码。
Disclaimer:免责声明:
As mentioned by rmaddy in his comments below, this is a hack and makes use of undocumented (Complete public API though) but a very well known hack to change the tint color of UISegemntedControl that exists from as far as iOS 5 (Thats how I remember, lemme know if I am wrong )正如rmaddy在下面的评论中所提到的,这是一个 hack 并利用了未记录的(尽管是完整的公共 API)但是一个众所周知的 hack 来更改从 iOS 5 就存在的 UISegemntedControl 的色调颜色(这就是我记得的,让我知道我是否错了)
So use answer with the caution in mind that, in future releases of iOS Apple might change the structure of subviews in UISegemntedControl
and might affect your O/P.因此请谨慎使用答案,在 iOS 的未来版本中,Apple可能会更改UISegemntedControl
视图的结构,并可能影响您的 O/P。 Nothing that I can see, will result in crash but might affect the way O/P is rendered on screen.我看不到的任何东西都会导致崩溃,但可能会影响 O/P 在屏幕上的呈现方式。
I have declared a variable so that GradientImage can be generated only once, but its up to your implementation to use it the way you want我已经声明了一个变量,以便 GradientImage 只能生成一次,但是取决于您的实现以您想要的方式使用它
var gradientImage : UIImage! = nil
In ViewDidLoad
I initialize the gradientImage
and UISegmentedControl
as在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()
}
Finally updateGradientBackground function definition is same as the one I posted in my original answer最后 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
}
}
}
Finally, in IBAction of UISegmentedControl, simply call最后,在 UISegmentedControl 的 IBAction 中,简单地调用
@IBAction func segmentControllerTapped(_ sender: UISegmentedControl) {
self.updateGradientBackground()
}
Hope this helps希望这可以帮助
Implemented gradient color for knob on iOS13+ UISegmentControl.在 iOS13+ UISegmentControl 上实现了旋钮的渐变颜色。 Added subview with gradient then set mask to it and copying animations to match original knob.添加带有渐变的子视图,然后为其设置遮罩并复制动画以匹配原始旋钮。
// 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)
}
}
}
}
}
This is not safe approach, because appearance will become invalid when apple will change control layout, but for now it is working.这不是安全的方法,因为当苹果更改控件布局时,外观将变得无效,但现在它正在工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.