前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[iOS]swift开发实现滚动切换Tab导航

[iOS]swift开发实现滚动切换Tab导航

原创
作者头像
柯柯哥
发布2023-12-22 14:37:03
2480
发布2023-12-22 14:37:03
举报
文章被收录于专栏:柯柯哥的开发心得

iOS开发中经常会遇到上方有一条Tab切换导航栏,点击Tab可以切换下方的页面显示。当Tab栏内元素显示超出一屏时就需要滚动显示,用户点击靠近边缘的item时就需要把屏幕外的元素滚动到屏幕内,以供用户选择,如果不滚动,那么用户就认为他点击的可能就是最后一个item,影响用户体验。具体实现就是scrollView。

大致效果如下:

先看下整个类的代码实现:

代码语言:swift
复制
import UIKit

protocol TabScrollViewDelegate : NSObjectProtocol {

    func didSelectOneTab(tabTitle:String,tabIndex:Int)

}

class TabScrollView: UIView {

/** 当前选中的Tab*/

    var selectTab:String=""

    /** 未选中状态下的标题颜色*/

    var normalTitleColor : UIColor = .white

    /** 选中状态下的标题颜色*/

    var selectedTitleColor : UIColor = .white

    /** 未选中状态下的标题字号*/

    var normalTitleFontSize : CGFloat  =13.0

    /** 选中状态下的标题字号*/

    var selectedTitleFontSize : CGFloat = 18.0

    /** 每个item之间的间距  */

    var itemSpacing :CGFloat = 16.0

    /** 选中Tab时候是否添加一个指示条*/

    var isShowBottomIndicatorLine : Bool = true

    /** 选中Tab时候添加指示条的颜色*/

    var indicatorLineColor : UIColor = .white

    /** 选中Tab时候添加指示条宽度,最多跟标题齐宽*/

    var indicatorWidth : CGFloat = 16.0

    /** 选中Tab时候添加指示条高度*/

    var indicatorHeight : CGFloat = 2.0

    /** 用户点击回传信息*/

    weak var delegate:TabScrollViewDelegate?

    var tabTitles: [String]?{

        didSet{

            guard let tabTitles = tabTitleselse{return}

            addTabItems(titleArray: tabTitles)

        }

    }

    private lazy var menuScrollView:UIScrollView = {

        let scrollView =UIScrollView(frame: .zero)

        scrollView.showsVerticalScrollIndicator = false;

        scrollView.showsHorizontalScrollIndicator = false;
        scrollView.alwaysBounceHorizontal=true;
       return scrollView

    }()

    override init(frame: CGRect) {

        super.init(frame: frame)

        backgroundColor = .white

        addChildViews()

    }

    //MARK: - 添加子视图

    private func addChildViews(){

        addSubview(menuScrollView)

        menuScrollView.frame = bounds

    }

    private func addTabItems(titleArray:[String]){

        let stackView =UIStackView()

        stackView.axis= .horizontal

        stackView.alignment= .center

        stackView.spacing=itemSpacing

        menuScrollView.addSubview(stackView)

        stackView.translatesAutoresizingMaskIntoConstraints = false

        stackView.heightAnchor.constraint(equalToConstant: menuScrollView.frame.height).isActive = true

        stackView.leftAnchor.constraint(equalTo: menuScrollView.leftAnchor).isActive = true



        for(index,menuItem)intitleArray.enumerated() {

            let itemStackView =UIStackView()

            itemStackView.axis= .vertical;

            itemStackView.alignment= .center;

            itemStackView.distribution= .equalSpacing;

            itemStackView.spacing=2.0;

            itemStackView.tag= index +100;

            let tapGesture =UITapGestureRecognizer(target:self,action:#selector(clickToSelectOneModule(tapGesture:)))

            itemStackView.addGestureRecognizer(tapGesture);

            stackView.addArrangedSubview(itemStackView);



            let menuBtn =UIButton();

            menuBtn.setTitle(menuItem,for: .normal);

            if(menuItem ==selectTab)

            {

                menuBtn.titleLabel?.font= .boldSystemFont(ofSize:selectedTitleFontSize);

                menuBtn.setTitleColor(normalTitleColor,for: .selected);

            }

            else

            {

                menuBtn.titleLabel?.font= .systemFont(ofSize:normalTitleFontSize);

                menuBtn.contentEdgeInsets = UIEdgeInsets(top: (frame.size.height - normalTitleFontSize) / 2.0, left: 0, bottom: (frame.size.height - normalTitleFontSize) / 2.0, right: 0);

                menuBtn.setTitleColor(normalTitleColor,for: .normal);

            }





            menuBtn.setContentHuggingPriority(UILayoutPriority(98), for: .horizontal);

            itemStackView.addArrangedSubview(menuBtn);

            menuBtn.isUserInteractionEnabled=false;

            //            看是否选中

            if(menuItem ==selectTab)

            {

                if(isShowBottomIndicatorLine)

                {

                    let lineView =UIView();

                    lineView.backgroundColor=indicatorLineColor;

                    itemStackView.addArrangedSubview(lineView);

                    lineView.translatesAutoresizingMaskIntoConstraints = false;

                    lineView.widthAnchor.constraint(equalToConstant: indicatorWidth).isActive = true;

                    lineView.heightAnchor.constraint(equalToConstant: indicatorHeight).isActive = true;

                    lineView.setContentHuggingPriority(UILayoutPriority(99),for: .horizontal);

                    lineView.centerXAnchor.constraint(equalTo: itemStackView.centerXAnchor).isActive=true;

                }



            }

        }

        stackView.layoutIfNeeded();

        menuScrollView.contentSize = CGSize(width: stackView.frame.width, height: menuScrollView.frame.height);

    }

    //MARK: 选中某个模块

    @objc private func clickToSelectOneModule(tapGesture:UITapGestureRecognizer)

    {

        guard let gestureView = tapGesture.view,letactiveModules =tabTitleselse{return}

        let moduleIndex = gestureView.tag-100;

        let activeModule = activeModules[moduleIndex];

        selectTab= activeModule;

        var scrollVisibleIndex =0;

        var needScroll =true;

        //

        if let previousView = gestureView.superview?.viewWithTag(moduleIndex -1+100)

        {

            if let nextView = gestureView.superview?.viewWithTag(moduleIndex +1+100)

            {

                //如果当前点击的模块前后模块都完整展示,那么就不需要做偏移

                if(previousView.frame.origin.x>=menuScrollView.contentOffset.x&& (menuScrollView.contentOffset.x>= (nextView.frame.origin.x - (menuScrollView.frame.width- nextView.frame.width))))

                {

                    needScroll =false;

                }

                else

                {

                    if(gestureView.frame.origin.x>=menuScrollView.contentOffset.x+menuScrollView.frame.width*0.5)

                    {

                        scrollVisibleIndex = nextView.tag;

                    }

                    else

                    {

                        scrollVisibleIndex = previousView.tag;

                    }

                }

            }

            else

            {

                //点击最后一个

                scrollVisibleIndex = gestureView.tag;

            }

        }

        else

        {

            //那就是点的第一个

            scrollVisibleIndex = gestureView.tag;

        }



        while menuScrollView.subviews.count>0{

            menuScrollView.subviews.last?.removeFromSuperview();

        }

        addTabItems(titleArray: activeModules);

        if let boxStackView =menuScrollView.subviews.last,letvisibleItem = boxStackView.viewWithTag(scrollVisibleIndex),needScroll

        {

            menuScrollView.scrollRectToVisible(visibleItem.frame,animated:true);

        }

        print("选中模块=\(activeModule)");

        delegate?.didSelectOneTab(tabTitle: activeModule,tabIndex: moduleIndex);

    }

    requiredinit?(coder:NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }

}

使用方法:

代码语言:swift
复制
let tabScrollView = TabScrollView(frame: CGRectMake(16.0, 200.0, UIScreen.main.bounds.width - 32.0, 28.0))
        tabScrollView.backgroundColor = .orange
        view.addSubview(tabScrollView)
        tabScrollView.selectTab = "推荐"
        tabScrollView.tabTitles = ["推荐","大厂动态","时政新闻","民生","军事","财经","历史故事","经济胡侃","今日说法"]
        tabScrollView.delegate = self

然后实现代理方法,用户选中某个Tab的信息就会在代理方法中回传,可以依据回传的信息做出相应的UI调整。

代码语言:swift
复制
func didSelectOneTab(tabTitle: String, tabIndex: Int) {
        print("选中 \(tabTitle),index = \(tabIndex)")
    }

需要说明的是,里边的一些属性设置想要生效的话必须在对tabTitles赋值前就自定义好。希望这些拙劣的代码能帮助你。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档