iOS自定义控件:分段选择器-Swift

2018-10-18  本文已影响52人  今晚月色
镇楼专用

废话不多说,直接上代码

1、数据源方法
// MARK: ============ SegmentSelectorManagerDataSource ============
@objc protocol  SegmentSelectorManagerDataSource:NSObjectProtocol {
    
    /// 主要配置 -> 必须要实现
    func nameOfSliderItems(segemntControl:SegmentSelectorManager) -> Array<String>
    func childViewControllers(segemntControl:SegmentSelectorManager) -> Array<UIViewController>
    
    /// 字体颜色配置 -> 有默认
    @objc optional func colorOfSlider(segemntControl:SegmentSelectorManager) -> UIColor
    @objc optional func colorOfTopView(segemntControl:SegmentSelectorManager) -> UIColor
    
    /// 背景颜色配置 -> 有默认
    @objc optional func colorOfSliderItemsTitle(segemntControl:SegmentSelectorManager) -> UIColor
    @objc optional func colorOfHighlightedSliderItemsTitle(segemntControl:SegmentSelectorManager) -> UIColor
    
    /// 高度配置 -> 有默认
    @objc optional func heightOfTopView(segemntControl:SegmentSelectorManager) -> CGFloat
    @objc optional func heightOfSlider(segemntControl:SegmentSelectorManager) -> CGFloat
}
2、代理方法
// MARK: ============ SegmentSelectorManagerDelegate ============
protocol SegmentSelectorManagerDelegate {
    func slideView(sliderView:SegmentSelectorManager, didSelectItemAtIndex:Int) -> Void
}
3、页面实现
override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    /// 数据源
    public weak var dataSource:SegmentSelectorManagerDataSource? {
        didSet {
            // 名称数组
            namesOfSlideItems = dataSource?.nameOfSliderItems(segemntControl: self)
            // 控制器数组
            childControllersArray = dataSource?.childViewControllers(segemntControl: self)
            
            if let ds = dataSource {

                if (ds.responds(to: #selector(ds.colorOfHighlightedSliderItemsTitle(segemntControl:)))) {
                    //按钮字体颜色默认
                    colorOfSlideItemsTitle = ds.colorOfSliderItemsTitle!(segemntControl: self)
                }
            
                if (ds.responds(to: #selector(ds.colorOfHighlightedSliderItemsTitle(segemntControl:)))) {
                    // 按钮字体颜色选中
                    colorOfHighlightedSlideItemsTitle = ds.colorOfHighlightedSliderItemsTitle!(segemntControl: self)
                }
                
                if (ds.responds(to: #selector(ds.colorOfSlider(segemntControl:)))) {
                    // 指示器颜色
                    colorOfSlider = ds.colorOfSlider!(segemntControl: self)
                }
                
                if ds.responds(to: #selector(ds.heightOfTopView(segemntControl:))) {
                    // 顶部视图高度
                    heightOfTopView = (ds.heightOfTopView!(segemntControl: self))
                }
                
                if ds.responds(to: #selector(ds.heightOfTopView(segemntControl:))) {
                    // 指示器高度
                    heightOfSlider = (ds.heightOfSlider!(segemntControl: self))
                }
            }
        }
    }
    
    // 代理
    public var delegate:SegmentSelectorManagerDelegate?
    
    var namesOfSlideItems: Array<String>? = []                           // 名称数组
    var colorOfSlider: UIColor? =  UIColor.orange                        // 指示器颜色
    var colorOfSlideView: UIColor? = UIColor.white                       // 顶部视图颜色
    var colorOfSlideItemsTitle: UIColor? = UIColor.gray                  // 默认字体颜色
    var colorOfHighlightedSlideItemsTitle: UIColor? = UIColor.orange     // 选中字体颜色
    var heightOfTopView:CGFloat = 45                                     // 顶部视图高度
    var heightOfSlider:CGFloat = 2                                       // 指示器高度
    let SliderThanSliderView_WidthRatio:CGFloat = 1                      // 按钮和指示器宽度比
    var buttonsArray:Array<UIButton>? = []                               // 所有按钮的数组
    var childControllersArray:Array<UIViewController>? = []              // 控制器数组
    
    let SCREEN_WIDTH = UIScreen.main.bounds.size.width
    let SCREEN_HEIGHT = UIScreen.main.bounds.height
    
    /// 顶部View
    lazy var slideBar:UIView = {
        let view = UIView.init()
        view.backgroundColor = colorOfSlideView
        addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        view.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        view.topAnchor.constraint(equalTo: topAnchor).isActive = true
        view.heightAnchor.constraint(equalToConstant: self.heightOfTopView).isActive = true
        return view
    }()
    
    // 底部指示器
    var slider:UIView?
    
    /// 控制器ScrollView
    lazy var contentScrollView:UIScrollView = {
        let sc = UIScrollView.init()
        sc.isDirectionalLockEnabled = true
        sc.backgroundColor = UIColor.white
        sc.isPagingEnabled = true
        sc.showsHorizontalScrollIndicator = false
        sc.delegate = self
        sc.bounces = false
        addSubview(sc)
        sc.translatesAutoresizingMaskIntoConstraints = false
        sc.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        sc.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        sc.topAnchor.constraint(equalTo: self.slideBar.bottomAnchor).isActive = true
        sc.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        return sc
    }()
4、绘制页面UI
    // 获取当前页面的控制器
    public func viewController()->UIViewController? {
        var nextResponder: UIResponder? = self
        repeat {
            nextResponder = nextResponder?.next
            if let viewController = nextResponder as? UIViewController {
                return viewController
            }
        } while nextResponder != nil
        
        return nil
    }

override func layoutSubviews() {
        super.layoutSubviews()
        addSlider()
        addButton()
        addContentScrollView()
    }
/// 添加按钮到顶部视图
    func addButton() {
        
        let numberOfItems:Int = (namesOfSlideItems?.count)!
        let slideItemWidth = SCREEN_WIDTH / CGFloat(numberOfItems)
        let sliderWidth = slideItemWidth * SliderThanSliderView_WidthRatio
        let position_x = (slideItemWidth - sliderWidth) / 2.0
        
        for index in 0..<numberOfItems {
            let b = UIButton.init(type: .custom)
            b.tag = index
            b.setTitle(namesOfSlideItems![index], for: .normal)
            b.setTitleColor(colorOfSlideItemsTitle, for: .normal)
            b.titleLabel?.textAlignment = .center
            b.addTarget(self, action: #selector(buttonTouched(button:)), for: .touchUpInside)
            buttonsArray?.append(b)
            b.frame = CGRect(x: position_x + slideItemWidth * CGFloat(index),
                             y: 5,
                             width: sliderWidth,
                             height: heightOfTopView-5)
            slideBar.addSubview(b)
            
            if index == 0 {
                b.setTitleColor(colorOfHighlightedSlideItemsTitle!, for: .normal)
            }
        }
    }
    
    // 添加底部指示器到顶部视图
    func addSlider() {
        let slideItemWidth =  SCREEN_WIDTH / CGFloat((namesOfSlideItems?.count)!)
        let sliderWidth = slideItemWidth * SliderThanSliderView_WidthRatio
        let position_x = (slideItemWidth - sliderWidth) / 2.0
        slideBar.addSubview(sliderView(frame: CGRect(x: position_x,
                                                     y: heightOfTopView - heightOfSlider,
                                                     width: sliderWidth,
                                                     height: heightOfSlider)))
        slideBar.backgroundColor = colorOfSlideView
        slider?.backgroundColor = colorOfSlider
    }
    
     // 添加ScrollView
    func addContentScrollView() {
        contentScrollView.contentSize = CGSize(width: SCREEN_WIDTH * CGFloat((namesOfSlideItems?.count)!), height: 0)

        for (index) in (childControllersArray?.enumerated())! {
            index.element.view.frame = CGRect(x: CGFloat(index.offset) * SCREEN_WIDTH,
                                              y: 0,
                                              width: contentScrollView.frame.width,
                                              height: contentScrollView.frame.height)
            contentScrollView.addSubview(index.element.view)
            viewController()?.addChild(index.element)
            index.element.didMove(toParent: viewController())
        }
    }
    
    // vc滚动动画
    func animateSlider(tag:Int) -> Void {
        contentScrollView.setContentOffset(CGPoint(x: SCREEN_WIDTH * CGFloat(tag), y: 0), animated: true)
    }
    
    // 指示器滚动动画
    func animateSliderToPosition(offset:CGPoint) -> Void {
        
        let slideItemWidth =  SCREEN_WIDTH / CGFloat((namesOfSlideItems?.count)!)
        let sliderWidth =  slideItemWidth * SliderThanSliderView_WidthRatio
        let position_x =  (slideItemWidth - sliderWidth) / 2.0
        
        let newFrame = CGRect(x: (offset.x / SCREEN_WIDTH) * slideItemWidth + position_x,
                              y: (slider?.frame.origin.y)!,
                              width: (slider?.frame.width)!,
                              height: (slider?.frame.height)!)
        slider?.frame = newFrame
        
        for (index) in (buttonsArray?.enumerated())! {
            index.element.setTitleColor(colorOfSlideItemsTitle, for: .normal)
        }
        
        var buttonTag = 0
        let ratio = offset.x / SCREEN_WIDTH
        let tempRation = Int(ratio)
        
        let decimal:CGFloat = ratio - CGFloat(tempRation)

        if decimal >= 0.5 {
            buttonTag = Int(ratio) + 1
        } else {
            buttonTag = Int(ratio)
        }
        
        buttonsArray![buttonTag].setTitleColor(colorOfHighlightedSlideItemsTitle, for: .normal)
    }
    
    /// 根据frame初始化指示器
    func sliderView(frame:CGRect) -> UIView {
        slider = UIView.init(frame: frame)
        return slider!
    }
   
    /// 点击事件
    @objc func buttonTouched(button:UIButton) {
        delegate?.slideView(sliderView: self, didSelectItemAtIndex: button.tag)
        animateSlider(tag: tag)
        contentScrollView.setContentOffset(CGPoint(x: SCREEN_WIDTH * CGFloat(button.tag), y: 0), animated: true)
    }
5、使用Extension实现UIScrollViewDidScrollDelegate
// MARK: ============ UIScrollViewDidScrollDelegate ============
extension SegmentSelectorManager:UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        animateSliderToPosition(offset: scrollView.contentOffset)
    }
}
6、使用方法(实例代码)
override func setupSubViewsProperties() {
        segmentView = SegmentSelectorManager.init(frame: CGRect.zero)
        segmentView?.delegate = self
        segmentView?.dataSource = self
        view.addSubview(segmentView!)
    }
    
    override func setupSubViewsConstrains() {
        if let seg = segmentView {
            seg.translatesAutoresizingMaskIntoConstraints = false
            seg.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            seg.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            seg.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -kTabBarHeight).isActive = true
            seg.topAnchor.constraint(equalTo: wd_navgationBar_normal.bottomAnchor).isActive = true
        }
    }

extension HotPlayController: SegmentSelectorManagerDataSource {

    func nameOfSliderItems(segemntControl: SegmentSelectorManager) -> Array<String> {
        return ["正在热映", "即将上映"]
    }
    
    func childViewControllers(segemntControl: SegmentSelectorManager) -> Array<UIViewController> {
        return [HotPlayingController(), HotWillPlayViewController()]
    }
    
    func heightOfTopView(segemntControl: SegmentSelectorManager) -> CGFloat {
        return 45
    }

    func heightOfSlider(segemntControl: SegmentSelectorManager) -> CGFloat {
        return 3
    }

    func colorOfSlider(segemntControl slider: SegmentSelectorManager) -> UIColor {
        return UIColor.wd_init(r: 73, g: 73, b: 73)
    }

    func colorOfTopView(segemntControl: SegmentSelectorManager) -> UIColor {
        return UIColor.white
    }

    func colorOfSliderItemsTitle(segemntControl: SegmentSelectorManager) -> UIColor {
        return UIColor.gray
    }

    func colorOfHighlightedSliderItemsTitle(segemntControl: SegmentSelectorManager) -> UIColor {
        return UIColor.wd_init(r: 73, g: 73, b: 73)
    }
}

extension HotPlayController: SegmentSelectorManagerDelegate {
    func slideView(sliderView: SegmentSelectorManager, didSelectItemAtIndex: Int) {
        
    }
}
7、效果图
效果图.gif
上一篇下一篇

猜你喜欢

热点阅读