菜单封装

这个菜单选择的代码 点击滚动  滑动滚动 

//
//  HWPageMenuView.swift
//  swift项目
//
//  Created by mac on 2019/10/29.
//  Copyright © 2019 mac. All rights reserved.
//

import UIKit
public enum HWMenuAligment:Int {
    case Left = 0
    case Center
}
 open class HWPageMenuView: UIView {

     open var customHeight:CGFloat = 44.0
        open var items:Array = []
        open var normalTextColor = UIColor.gray{
            didSet{
                self.buttons.forEach { (btn) in
                    btn.setTitleColor(self.normalTextColor, for: .normal)
                }
            }
        }
    //    open var
        open var selectedTextColor = UIColor.black {
            didSet{
                self.buttons.forEach { (btn) in
                    btn.setTitleColor(self.selectedTextColor, for: .selected)
                    btn.setTitleColor(self.selectedTextColor, for: .highlighted)
                }
            }
        }
        open var normalTextFont = UIFont.systemFont(ofSize: 14) {
            didSet{
                self.buttons.forEach { (btn) in
                    if btn != self.selectedBtn {
                        btn.titleLabel?.font = self.normalTextFont
                    }
                }
            }
        }
        open var selectedTextFont = UIFont.systemFont(ofSize: 18){
            didSet{
                self.selectedBtn.titleLabel?.font = self.normalTextFont
            }
        }
        open var borderColor = UIColor.blue {
            didSet{
                self.selectLayer.backgroundColor=borderColor.cgColor
            }
        }
        open var borderSize = CGSize(width: 30, height: 2) {
            didSet{
                self.selectLayer.frame = CGRect(origin: self.selectLayer.frame.origin, size:borderSize )
            }
        }
        open var itemMargin:CGFloat = 5
        open var aligment:HWMenuAligment = .Center //只有当总宽度小于容器宽度才有效
       
        //private
        //如果需要selectedIndex值。请调用SYContainerViewController的selectedIndex属性
        private var selectedIndex = 0
        private var scrollView:UIScrollView = {
            var scroll = UIScrollView()
            scroll.scrollsToTop=false
            scroll.bounces=false
            scroll.showsVerticalScrollIndicator=false
            scroll.showsHorizontalScrollIndicator=false
            scroll.contentInset=UIEdgeInsets.zero
            scroll.backgroundColor=UIColor.clear
            return scroll
        }()
        private var selectLayer:CALayer = {
            var layer = CALayer ()
            layer.backgroundColor = UIColor.blue.cgColor
            layer.frame = CGRect(x: 0, y: 0, width: 30, height: 2)
            return layer
        }()
        
        private var buttonFrames:Array=[]
        private var selectedBtn:UIButton!
        private var buttons:Array = []
        
        var block:((_ selectedIndex:Int) -> Void)!
        convenience init(block:@escaping ((_ selectedIndex:Int) -> Void)) {
            self.init()
            self.addSubview(self.scrollView)
            self.scrollView.layer.addSublayer(self.selectLayer)
            self.selectLayer.backgroundColor=self.borderColor.cgColor
            self.block=block
        }
        
        func setItems(_ items:Array) {
            self.items = items
            self.buttonFrames=[]//清空
            
            self.buttons.forEach { (btn) in
                btn.removeFromSuperview()
            }
            self.buttons=[]//清空
            self.items.forEach { (title) in
                let btn = UIButton()
                btn.setTitle(title, for: .normal)
                btn.addTarget(self, action: #selector(self.btnClick(sender:)), for: .touchUpInside)
                btn.setTitleColor(self.normalTextColor, for: .normal)
                btn.setTitleColor(self.selectedTextColor, for: .selected)
                btn.setTitleColor(self.selectedTextColor, for: .highlighted)
                btn.titleLabel?.font = self.normalTextFont
                btn.titleLabel?.textAlignment = .center
                btn.tag=self.buttons.count//刚好一一对应
                self.scrollView.addSubview(btn)
                self.buttons.append(btn)
                let key = title as NSString
                let frame = key.boundingRect(with: CGSize(width: 0, height: 30), options: [.usesLineFragmentOrigin,.usesFontLeading], attributes: [NSAttributedString.Key.font:self.selectedTextFont], context: nil)
                self.buttonFrames.append(frame.size.width)
                
    //            frame = key.boundingRect(with: CGSize(width: 0, height: 30), options: [NSStringDrawingOptions.usesLineFragmentOrigin,NSStringDrawingOptions.usesFontLeading], attributes: [NSAttributedString.Key.font : self.sel]?, context: <#T##NSStringDrawingContext?#>)
                
            }
            //设置默认选项
            self.selectedBtn=self.buttons.first
            self.selectedBtn.isSelected = true
            self.selectedBtn.titleLabel?.font = self.selectedTextFont
            //重新布局
            self.setNeedsLayout()
        }
        
        func setSelectedItemIndex(_ index:Int) {
            if selectedIndex == index {
                return
            }
            self.selectedIndex=index
            self.selectedBtn.isSelected = false
            HWAnimation.scaleAnimation(layer: self.selectedBtn.layer, from: 1.1, to: 1.0, duration: 0.35, remove: false, repeats: 1)
            self.selectedBtn.titleLabel?.font = self.normalTextFont
            self.selectedBtn = self.buttons[index]
            self.selectedBtn.isSelected = true
            self.selectedBtn.titleLabel?.font = self.selectedTextFont
            HWAnimation.scaleAnimation(layer: self.selectedBtn.layer, from: 0.9, to: 1.0, duration: 0.35, remove: false, repeats: 1)
            self.updateOffset(btn: self.selectedBtn)
        }
        
        @objc func btnClick(sender:UIButton) {
            if self.selectedBtn == sender {
                return
            }
            self.setSelectedItemIndex(sender.tag)
            
            block(sender.tag)
        }
        
        //设置选中的button居中
        func updateOffset(btn:UIButton) {
            let offsetX:CGFloat = btn.center.x+self.frame.origin.x - self.center.x;
            var point:CGPoint
            if (offsetX < 0){
                point = CGPoint(x: 0, y: 0)
            }else if (offsetX > (scrollView.contentSize.width - self.bounds.size.width)){
                point = CGPoint(x:scrollView.contentSize.width - self.bounds.size.width , y: 0)
            }else{
                point = CGPoint(x: offsetX, y: 0)
            }
            
            UIView.animate(withDuration: 0.4) {
                self.scrollView.contentOffset=point
            }
            self.selectLayer.position = CGPoint(x: self.selectedBtn.center.x, y: self.frame.size.height-self.selectLayer.frame.size.height-1)
        }
        
        open override func layoutSubviews() {
            super.layoutSubviews()
            
            self.scrollView.frame=self.bounds
            
            let sum = self.buttonFrames.reduce(0) { $0 + $1 }
            if self.aligment == .Left || sum>self.frame.size.width {
                var x:CGFloat = itemMargin , height = self.frame.size.height
                for (index,item) in self.buttons.enumerated() {
                    item.frame=CGRect(x: x, y: 0, width: self.buttonFrames[index]+itemMargin, height: height)
                    x=item.frame.maxX
                }
                self.scrollView.contentSize=CGSize(width: x, height: height)
            }else{
                var x:CGFloat = 0 , height = self.frame.size.height , width = self.frame.size.width/CGFloat(self.buttonFrames.count)
                for (_,item) in self.buttons.enumerated() {
                    item.frame=CGRect(x: x, y: 0, width: width, height: height)
                    x=item.frame.maxX
                }
                self.scrollView.contentSize=self.frame.size
            }
            
            self.selectLayer.position = CGPoint(x: self.selectedBtn.center.x, y: self.frame.size.height-self.selectLayer.frame.size.height-1)
            
        }

}
这个是 添加控制器的代码  
//
//  HWPageViewController.swift
//  swift项目
//
//  Created by mac on 2019/10/29.
//  Copyright © 2019 mac. All rights reserved.
//

import UIKit
let HWCellId = "HWCellId"
class HWPageViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate {

    private var collectionView:UICollectionView!
        private lazy var flowLayout=UICollectionViewFlowLayout()
        
        open var viewControllers:Array=[]
        open var selectedIndex = 0
        
        open var vcSelectedIndex: Int? {
            didSet {
                self.setSelectedIndex(index: self.vcSelectedIndex!)
            }
        }
        open var currentController:UIViewController{
            get{
                return self.viewControllers[self.selectedIndex]
            }
        }
        
        //可能会被自定义
    //   open lazy var menuView = HWPageMenuView {
    //        [unowned self]
    //        (index) in
    //        self.willSelectControllerAtIndex(index: index)
    //        self.didSelectControllerAtIndex(index: index)
    //
    //    }
        open lazy var menuView = HWPageMenuView.init { (index) in
            
            self.willSelectControllerAtIndex(index: index)
            self.didSelectControllerAtIndex(index: index)
        }
        
        // MARK: 生命周期方法
        open override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            self.currentController.beginAppearanceTransition(true, animated: animated)
        }
        open override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            self.currentController.endAppearanceTransition()
            self.updateCollectViewSelection()
        }
        open override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            self.currentController.beginAppearanceTransition(false, animated: animated)
        }
        open override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
            self.currentController.endAppearanceTransition()
        }
        
        open override func viewDidLoad() {
            super.viewDidLoad()
            if self.responds(to: #selector(setter: edgesForExtendedLayout)) {
                self.edgesForExtendedLayout = []
            }
            self.extendedLayoutIncludesOpaqueBars = false
            self.setupUI()
        }
        
        open override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            
            let size = self.view.frame.size
            self.menuView.frame=CGRect(x: 0, y: 0, width: size.width, height: self.menuView.customHeight)
            self.flowLayout.itemSize = CGSize(width: size.width, height: size.height-self.menuView.frame.maxY)
            self.collectionView.frame = CGRect(x: 0, y: self.menuView.frame.maxY, width: size.width, height: size.height-self.menuView.frame.maxY)
        }
        
        open override var shouldAutomaticallyForwardAppearanceMethods: Bool{
            return false
        }
        // MARK: custom func
        private func setupUI() {
            self.view.addSubview(self.menuView)
            
            self.flowLayout.scrollDirection = .horizontal
            self.flowLayout.minimumLineSpacing = 0
            self.flowLayout.minimumInteritemSpacing = 0
            
            self.collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: self.flowLayout)
            self.view.addSubview(self.collectionView)
            self.collectionView.isPagingEnabled=true
            if #available(iOS 10.0, *) {
                self.collectionView.isPrefetchingEnabled = true
            }
            self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: HWCellId)
            self.collectionView.delegate=self
            self.collectionView.dataSource=self
            self.collectionView.showsHorizontalScrollIndicator = false
            self.collectionView.showsVerticalScrollIndicator = false
            self.collectionView.scrollsToTop = false
            self.collectionView.backgroundColor=UIColor.white
        }
        
        open func setupVCsDataSources(viewControllers:Array) {
            if viewControllers.count == 0 {
                assert(true, "viewControllers不能为空")
                return
            }
            self.viewControllers = viewControllers
            self.viewControllers.forEach { (vc) in
                self.addChild(vc)
                
            }
            let items = self.viewControllers.map { (vc:UIViewController) -> String in
                return vc.title ?? ""
            }
            self.menuView.setItems(items)
            self.menuView.setSelectedItemIndex(0)
            
            self.reLoadDataSources()
            
        }
        
        open func reLoadDataSources() {
            assert(self.viewControllers.count != 0, "缺少子视图,请调用 setupVCsDataSources(:)函数进行初始化")
            self.collectionView.reloadData()
        }
        //设置当前选中项
        open func setSelectedIndex(index:Int) {
            if self.viewControllers.count>index {
                selectedIndex = index
                self.menuView.setSelectedItemIndex(index)
                self.updateCollectViewSelection()
            }
        }
        open func willSelectControllerAtIndex(index:Int) {
            self.selectedIndex = index
            self.updateCollectViewSelection()
        }

        open func didSelectControllerAtIndex(index:Int) {
            
        }
        func updateCollectViewSelection() {
            let size = self.view.bounds.size
            let offsetX = size.width * CGFloat(selectedIndex)
            self.collectionView.contentOffset = CGPoint(x: offsetX, y: 0)
        }
        
        
        public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return self.viewControllers.count
        }
        public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HWCellId, for: indexPath)
            cell.contentView.subviews.forEach { (view) in
                view.removeFromSuperview()
            }
            let subView = self.viewControllers[indexPath.row].view!
            subView.frame=cell.bounds
            cell.contentView.addSubview(subView)
            return cell
        }
        
        public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
            let vc = self.viewControllers[indexPath.row]
            vc.beginAppearanceTransition(true, animated: true)
            vc.endAppearanceTransition()
        }
        public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
            let vc = self.viewControllers[indexPath.row]
            vc.beginAppearanceTransition(false, animated: true)
            vc.endAppearanceTransition()
        }
        
        public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            let size = self.view.bounds.size
            let index = Int(scrollView.contentOffset.x / size.width)
            selectedIndex = index
            self.menuView.setSelectedItemIndex(index)
            self.didSelectControllerAtIndex(index: index)
        }
    

}

外界使用时 只需要继承 HWPageViewController  并实现 self.setupVCsDataSources(viewControllers: arr)这个方法  前提将添加的控制器 添加到 arr数组里面,并暴露了 多个属性可供设置比如 下划线的颜色 高度,宽度,选择文字的颜色 字体大小,默认选中哪个控制器 等。水平有限,不足之处还望指正。

你可能感兴趣的:(菜单封装)