分段控件中的渐变色 [英] Gradient tint color in segmented control

查看:178
本文介绍了分段控件中的渐变色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用这种方法得到了梯度图像

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()
}

然后我将分段控件的tintColor设置为渐变:

Then I set tintColor of segmented control to gradient:

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

那是行不通的.但是,相同的代码可用于设置backgroundColor:

and that doesn't work. However, same code works for setting backgroundColor:

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

有人有什么想法吗?我真的需要设置渐变tintColor.任何帮助都非常感谢.

Does anybody have any ideas why? I really need to set gradient tintColor. Any help is very appreciated.

理想情况下,我希望分段控件看起来像这样:

Ideally I want my segmented control to look like this:

推荐答案

这是一种已知的用于更改UISegmentedControl

This is a known hack to change the tint color of 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.

这是您需要的伙伴吗?

如果知道是,我将发布相同的代码.

If yes lemme know, Ill post the code for the same.

正如OP在他的评论中提到的那样,他期望的输出与我在上图中显示的输出相同,并提供相同的代码.

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.

免责声明:

rmaddy 在下面的评论中所述,这是一种黑客行为,并利用了未公开的文档(尽管完整的公共API ),但是它是一个非常著名的黑客,它可以更改从iOS 5开始就存在的UISegemntedControl的颜色(这就是我所记得的,让我知道我是否错了)

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 )

因此,请谨慎使用答案,因为在将来的iOS苹果Apple 可能中,更改UISegemntedControl中子视图的结构可能会影响您的O/P.我看不到任何东西会导致崩溃,但可能会影响O/P在屏幕上的呈现方式.

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. Nothing that I can see, will result in crash but might affect the way O/P is rendered on screen.

我已经声明了一个变量,因此GradientImage只能生成一次,但是取决于您的实现以所需的方式使用它

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

var gradientImage : UIImage! = nil

ViewDidLoad中,我将gradientImageUISegmentedControl初始化为

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函数定义与我在原始答案中发布的函数定义相同

Finally updateGradientBackground function definition is same as the one I posted in my original answer

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
            }
        }
    }

最后,在UISegmentedControl的IBAction中,只需调用

Finally, in IBAction of UISegmentedControl, simply call

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

希望这会有所帮助

这篇关于分段控件中的渐变色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆