美文网首页UI
UISegmentedControl

UISegmentedControl

作者: coenen | 来源:发表于2020-05-18 20:47 被阅读0次

    说起SegmentedControl大家都比较熟悉了,在项目中百分之八十都会用到.在这里我们简单了解一下吧.

    针对这样的实现你会怎么做呢?


    1.png
    2.png
    3.png

    本来是不打算写这篇文章的,毕竟觉得市面上软文比较多.我是在review代码的时候,发现一位小伙伴的天级用法(循环N个view)后,觉得还是写一下吧.经过我的调查发现,目前市面上普遍采用几种实现方式.

    第一种: UICollectionView
    这个的比较普遍,采用滚动视图的原理,加上一些逻辑判断.也算能实现产品的需求吧.这种的目前先不做大量阐述,只是简单说一下.

    很多都是文字实现,然后底部加一个图片,或者label来实现需求.比较常用也没什么弊端.

    第二种: UIScrollView + N个View
    这个是我看到的另一种写法,我本来以为是极个别.但是经过调查发现,大量什么XXSegmentedControl 的封装都是采用如此.我瞬间感觉整个人都不好了.
    是我的理解有误,还是大家目前都是这样一种堆砌的方式去实现需求呢?反过来问,对自己有什么意义吗?实在是百思不解其道.
    对于视图的写法我一般是不太喜欢管束太多的,但是有些很明显的东西,我还是期望按照正常的逻辑方式去实现.可以深挖,可以扩广,但是不能走其歪路.如果,一个人既没有深度,也没有广度,那我们深思一下,我们的优势在哪里呢?想着想着就唠偏了.如果第一种是还可以让人接受的方法的话,那么这种就是有点不忍直视了.不建议大家采用这样的写法或者这样的三方库去实现.对项目而已,增加大家的熟悉成本,对个人而言,毫无提升.

    第三种: 官方用法 UISegmentedControl

    因为项目中会有多个地方使用,所以为了方便,采用封装.
    LTMSegmentedControl: UISegmentedControl

    一些基本的配置

    配置默认颜色和字体

    func configNormalColorAndFont(normalColor: UIColor, normalFont: UIFont){
        let normalDic:NSDictionary = [NSAttributedString.Key.foregroundColor:normalColor,NSAttributedString.Key.font:normalFont];
        self.setTitleTextAttributes(normalDic as? [NSAttributedString.Key : Any], for: .normal)
    }
    

    配置选中颜色和字体

    func configSelectedColorAndFont(selectedColor: UIColor, selectedFont: UIFont){
        let selectedDic:NSDictionary = [NSAttributedString.Key.foregroundColor:selectedColor,NSAttributedString.Key.font:selectedFont];
        self.setTitleTextAttributes(selectedDic as? [NSAttributedString.Key : Any], for: .selected)
    }
    

    删除分割线

    func configRemoveDividerImage(){
        self.setDividerImage(UIImage.init(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
    

    设置背景色

    func configBackgroundImage(){
        self.setBackgroundImage(UIImage.init(color: UIColor.clear), for: .normal, barMetrics: .default)
    }
    

    在这解释一下为什么要做这个设置背景色的配置,因为如果不做背景设置的话,会有图层.图层会影响SegmentedControl的颜色.设置之后就是SegmentedControl的原背景色.

    颜色生成图片

    //MARK: - Image
    extension UIImage{
    //用颜色生成图片
    convenience init(color: UIColor) {
        let size = CGSize(width: 1, height: 1)
        UIGraphicsBeginImageContext(size)
        let path = UIBezierPath(rect: CGRect(origin: .zero, size: .zero))
        color.set()
        path.fill()
        let image :UIImage! = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image.cgImage)!)
    }
    
    //图片宽高百分比缩放
    func conver(quality: Float) -> UIImage? {
        if let data = self.jpegData(compressionQuality: CGFloat(quality)), let photo = UIImage(data: data) {
            return photo
        }
        return UIImage()
       }
    
    }
    

    补充 iOS13 适配

    我们都知道iOS更新了UISegmentedControl方法.
    在iOS13上会有圆角的显示,无论怎么设置layer都没办法隐藏圆角.
    这是为什么呢?
    通过查看,发现所有的子视图都设置了圆角效果.
    所以我们在加载的时候进行处理一下.进行重写layoutSubviews即可.

    open override func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = 0
    }
    

    这样一些基本的配置我们就实现了.

    接下来就是重点使用了.我们一般UISegmentedControl都不会单独使用,我们都会有配套的视图展示.
    我这里采用的是在SegmentedControl 下方添加UIScrollView.UIScrollView添加相应的视图.添加过程我们就不啰嗦了.
    我们这重点说一下联动.

    实现效果: 1、点击SegmentedControl后ScrollView滚动到相应位置

    这个比较简单,首先在点击实现里面进行滚动,通过控制ContentOffset进行UIScrollView的滚动.
    然后调用底部视图更新位置

    func changeUnderLineOrigin(index: Int, scroll: Bool){
        if isScroll == true{
            segment.selectedSegmentIndex = index
        }
        
        self.underLine.frame.origin.x = CGFloat(index) * self.view.frame.size.width/5 + self.view.frame.size.width/10 - 8.5
    }
    

    这样就可以正向实现了.

    实现效果: 2、滚动ScrollView,SegmentedControl自动选中相应item.

    首先我们理一下思路.通过计算滚动,然后让SegmentedControl进行选中.
    那么我们什么时候进行滚动计算呢?有的说在scrollViewDidScroll中进行,也有的说在滚动结束的时候进行.
    在这里我们先说一下我们的结论.如果涉及颜色变换的,采用滚动结束时进行计算.如果没有的话,都可以.
    为什么呢?因为颜色变化的话,你可能会颜色变换多次.

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let scrollToScrollStop: Bool = !scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating
        if scrollToScrollStop{
            self.scrollViewStop(scrollView)
        }
    }
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate{
            let dragToDragStop = scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating;
            if (dragToDragStop) {
                self.scrollViewStop(scrollView);
            }
        }
    }
    

    因为有不同的方法,所以这块综合处理.

    func scrollViewStop(_ scrollView: UIScrollView){
        let location = scrollView.contentOffset.x/self.view.frame.size.width
        var index = 0
        if (location < 0.5 ) {
               index = 0;
           } else if (location >= 0.5 && location <= 1) {
               index = 1;
           } else if (location > 1 && location <= 1.5) {
               index = 1;
           } else if (location > 1.5 && location <= 2) {
               index = 2;
           } else if (location > 2 && location <= 2.5) {
               index = 2;
           } else if (location > 2.5 && location <= 3) {
               index = 3;
           } else if (location > 3 && location <= 3.5) {
               index = 3;
           }else if (location > 3.5 && location <= 4) {
               index = 4;
           } else if (location > 4 && location <= 4.5) {
               index = 4;
           }
        isScroll = true
        self.changeUnderLineOrigin(index: index, scroll: true)
    }
    

    if 比较多,只是为了给大家更清晰的演示哈.

    在这里再增加最后一个重点.相信大家都看到了代码中有一个isScroll 布尔变量.那么这个有什么用呢?
    其实在前面给大家挖了一个坑,就是什么时候判断去设置SegmentedControl选中呢?如果我们不加这个判断呢?

    就会遇到我们之前说的颜色问题了.因为多次设置SegmentedControl选中.导致多次高亮.
    在这里只是说一些重点,相信大家都已经get到了.
    在前进的道路上希望大家采用正确的打开方式解锁各种花里胡哨的姿势,不要因小失大.

    说一千道一万,不如Demo转一转.
    希望大家喜欢哈.

    相关文章

      网友评论

        本文标题:UISegmentedControl

        本文链接:https://www.haomeiwen.com/subject/xpvpohtx.html