swift学习

iOS 13.0 添加UISegmentedControl 对图

2020-07-25  本文已影响0人  SoaringHeart

项目中经常遇到这种分割线隔开的分段按钮视图,将完美的实现方式总结记录一下(可以自定义视图,添加子视图的方式实现,但是那永远不是最好的选择,我试过 n 种)

WX20200725-113707@2x.png

但是官方默认只支持 UIImage 或者 String,only one!

open func setTitle(_ title: String?, forSegmentAt segment: Int) // can only have image or title, not both. must be 0..#segments - 1 (or ignored). default is nil
open func setImage(_ image: UIImage?, forSegmentAt segment: Int) // can only have image or title, not both. must be 0..#segments - 1 (or ignored). default is nil

所以需要自己思考如何 支持 both? 一种是重写 UISegmentedControl 分段子控件,在子控件视图进行绘制,肯定能实现需求,但是太复杂,思考是否有更加简单的办法?灵光一闪:直接设置 UIImage,在图像中包含所有信息不就 ok 了,随想随动:
第一步:图像绘制图像+文字:

@objc public extension UIImage {

    ///扩展便利构造器
    convenience init(color: UIColor) {
        let image = UIImage.color(color)
        if let cgImage = image.cgImage {
            self.init(cgImage: cgImage)
        } else {
            self.init(cgImage: UIImage.color(.white).cgImage!)
        }
    }
            
    /// 把颜色转成UIImage
    static func color(_ color: UIColor) -> UIImage{
        let size: CGSize = CGSize(width: 1, height: 1)
        let rect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        defer {
            UIGraphicsEndImageContext()
        }
        let context: CGContext = UIGraphicsGetCurrentContext()!
        context.setFillColor(color.cgColor)
        context.fill(rect)
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        return image ?? UIImage()
    }
    ///生成含有图片和文字的图像
    static func textEmbededImage(image: UIImage, string: String, color: UIColor, imageAlignment: Int = 0, segFont: UIFont? = nil) -> UIImage {
        let font = segFont ?? UIFont.systemFont(ofSize: 16.0)
        let expectedTextSize: CGSize = (string as NSString).size(withAttributes: [NSAttributedString.Key.font: font])
        let width: CGFloat = expectedTextSize.width + image.size.width + 5.0
        let height: CGFloat = max(expectedTextSize.height, image.size.width)
        let size: CGSize = CGSize(width: width, height: height)
        
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        let context: CGContext = UIGraphicsGetCurrentContext()!
        context.setFillColor(color.cgColor)
        let fontTopPosition: CGFloat = (height - expectedTextSize.height) / 2.0
        let textOrigin: CGFloat = (imageAlignment == 0) ? image.size.width + 5 : 0
        let textPoint: CGPoint = CGPoint(x: textOrigin, y: fontTopPosition)
        string.draw(at: textPoint, withAttributes: [NSAttributedString.Key.font: font,
                                                    NSAttributedString.Key.foregroundColor: color])
        
        let flipVertical: CGAffineTransform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height)
        context.concatenate(flipVertical)
        
        let alignment: CGFloat = (imageAlignment == 0) ? 0.0 : expectedTextSize.width + 5.0
        context.draw(image.cgImage!, in: CGRect(x: alignment,
                                                y: ((height - image.size.height) / 2.0),
                                                width: image.size.width,
                                                height: image.size.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

第二步:设置UISegmentedControl 外观

let clearColorImage = UIImage(color: .clear)
view.setBackgroundImage(clearColorImage, for: .normal, barMetrics: .default)
view.setBackgroundImage(clearColorImage, for: .selected, barMetrics: .default)
view.setBackgroundImage(clearColorImage, for: .highlighted, barMetrics: .default)
view.setDividerImage(UIImage(color: .line), forLeftSegmentState: [.normal, .selected, .highlighted], rightSegmentState: .normal, barMetrics: .default)

第三步:设置UISegmentedControl 图像

//图像必须 withRenderingMode(.alwaysOriginal) 选择原始渲染,不然会被 tintColor 渲染为纯色图片
cell.segmentCtl.setImage(UIImage(named: "icon_find_route")?.withRenderingMode(.alwaysOriginal), forSegmentAt: 0)       
cell.segmentCtl.setImage(UIImage(named: "icon_go_here")?.withRenderingMode(.alwaysOriginal), forSegmentAt: 1)

完美实现!!!

上一篇下一篇

猜你喜欢

热点阅读