Swift開發(fā):自定義標簽欄UITabBarController (Swift項目開始的第一步)

自定義UITabbarController進而自定義UITabbar射亏,這通常會是一個iOS項目開始的重要環(huán)節(jié)。在Swift的學習過程中,個人感覺雖說兩種語言的相似度很大,但是Swift依然在代碼風格上有著和OC很大的差異寡键。在總結(jié)了一些基本的用法之后,我嘗試使用Swift自定義UITabBarController和UITabbar雪隧,開啟這Siwft項目的關鍵一步西轩,首先展示一下效果圖:

屏幕快照 2017-07-15 下午2.40.54.png

第一步:創(chuàng)建Swift工程#

1.使用Xcode創(chuàng)建一個Swift初始項目ZSTestSwift,效果如下:


屏幕快照 2017-07-15 上午11.22.57.png

這里首先刪除工程文件下的ViewController.swift膀跌、Main.StoryBoard 和TARGETS下MainInterFace中的Main遭商,因為我們要使用純代碼的方式來創(chuàng)建標簽欄控制器,系統(tǒng)自帶Main.StoryBoard的xib形式的界面我們并不需要捅伤。

第二步:準備資源文件

1.在Assets.xcassets中存放標簽欄按鈕所需要的圖片資源


屏幕快照 2017-07-15 下午1.52.29.png

2.創(chuàng)建標簽配置Plist文件,并且在Plist文件中設置視圖控制器的類名巫玻、Title丛忆、標簽欄圖片等信息

屏幕快照 2017-07-15 下午1.46.26.png

這里做下說明祠汇,之所以創(chuàng)建這個plist文件是因為在之后創(chuàng)建視圖控制器和標簽按鈕時會有很大的便利性,而且也十分方便真實開發(fā)過程中的需求更改熄诡。

第三步:創(chuàng)建視圖控制器

自定義導航控制器和視圖控制器的父類可很,并且創(chuàng)建三個繼承于BaseViewController的視圖控制器(因為沒有過多復雜操作,這里省略代碼)凰浮,為之后創(chuàng)建標簽控制器做準備我抠。創(chuàng)建之后的效果如圖:

屏幕快照 2017-07-15 下午12.03.08.png

第四步:創(chuàng)建自定義的標簽視圖控制器和自定義UITabbar

1.創(chuàng)建自定義標簽控制器MainTabBarController,其關鍵代碼如下:

  class MainTabBarController: UITabBarController, MainTabBarDelegate{
    
    var tarbarConfigArr:[Dictionary<String,String>]! //標簽欄配置數(shù)組袜茧,從Plist文件中讀取
    var mainTabBarView: MainTabBarView! //自定義的底部TabbarView
    
    //MARK: - Life Cycle
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?){
        //1.調(diào)用父類的初始化方法
        super.init(nibName: nil, bundle: nil)
        //2.讀取Plist文件,初始化標簽欄配置數(shù)組
        self.tarbarConfigArr = self.getConfigArrFromPlistFile()
        //3.創(chuàng)建視圖控制器
        self.createControllers()
        //4.創(chuàng)建自定義TabBarView
        self.createMainTabBarView()
    }
    
    required init?(coder aDecoder: NSCoder){
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad(){
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool){
        super.viewWillAppear(animated)
    }
    
    
    //MARK: - Private Methods
    //讀取Tabbar配置文件
    private  func  getConfigArrFromPlistFile() ->([Dictionary<String,String>]?){
        let  filePath: String? = Bundle.main.path(forResource: "TabBarConfig", ofType: "plist")
        let plistData = NSDictionary(contentsOfFile: filePath ?? "")
        let configArr = plistData?.object(forKey: "Tabbars") as? [Dictionary<String,String>]
        return configArr;
    }

    //創(chuàng)建視圖控制器
    private func createControllers(){
        var controllerNameArray = [String]() //控制器類名數(shù)組
        var controllerTitle = [String]()     //控制器Title數(shù)組
        for dictionary in self.tarbarConfigArr{
            controllerNameArray.append(dictionary["ClassName"]!);
            controllerTitle.append(dictionary["Title"]!)
            
        guard controllerNameArray.count > 0 else{
            print("error:控制器數(shù)組為空")
            return
        }
        //初始化導航控制器數(shù)組
        var nvcArray = [BaseNavigationViewController]()
        //在Swift中, 通過字符串創(chuàng)建一個類, 那么必須加上命名空間clsName
        let clsName = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        for i in 0...controllerNameArray.count-1 {
            //動態(tài)獲取的命名空間是不包含.的, 所以需要我們自己手動拼接
            let anyClass: AnyClass? = NSClassFromString(clsName + "." + controllerNameArray[i])
            //將AnyClass類型轉(zhuǎn)換為BaseViewController類型菜拓,
            //因為Swift中通過一個Class來創(chuàng)建一個對象, 必須告訴系統(tǒng)這個Class的確切類型
            if let vcClassType = anyClass as? BaseViewController.Type {
                let viewcontroller = vcClassType.init()
                viewcontroller.title = controllerTitle[i]
                let nav = BaseNavigationViewController(rootViewController:viewcontroller)
                nvcArray.append(nav)
            }
        }
        //設置標簽欄控制器數(shù)組
        self.viewControllers = nvcArray
        }
    }

    //創(chuàng)建自定義Tabbar
    private func createMainTabBarView(){
        //1.獲取系統(tǒng)自帶的標簽欄視圖的frame,并將其設置為隱藏
        let tabBarRect = self.tabBar.frame;
        self.tabBar.isHidden = true;
        //3.使用得到的frame,和plist數(shù)據(jù)創(chuàng)建自定義標簽欄
        mainTabBarView = MainTabBarView(frame: tabBarRect,tabbarConfigArr:tarbarConfigArr!);
        mainTabBarView.delegate = self
        self.view .addSubview(mainTabBarView)
    }
    
    //MARK: - MainTabBarDelegate
    func didChooseItem(itemIndex: Int) {
        self.selectedIndex = itemIndex
    }
}

2.創(chuàng)建自定義的標簽欄MainTabBarView笛厦,其關鍵代碼如下:

  //自定義標簽欄代理協(xié)議
protocol MainTabBarDelegate {
    func didChooseItem(itemIndex:Int)
}

class MainTabBarView: UIView {
    var delegate:MainTabBarDelegate? //代理,點擊item
    var itemArray:[MainTabBarItem] = [] //標簽Item數(shù)組
   
    init(frame: CGRect,tabbarConfigArr:[Dictionary<String,String>]) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.white
        let screenW = UIScreen.main.bounds.size.width
        let itemWidth = screenW / CGFloat(tabbarConfigArr.count)
        for i in 0..<tabbarConfigArr.count{
            let itemDic = tabbarConfigArr[i];
            let itemFrame = CGRect(x: itemWidth * CGFloat(i) , y: 0, width: itemWidth, height: frame.size.height)
            //創(chuàng)建Item視圖
            let itemView = MainTabBarItem(frame: itemFrame, itemDic:itemDic, itemIndex: i)
            self.addSubview(itemView)
            self.itemArray.append(itemView)
            //添加事件點擊處理
            itemView.tag = i
            itemView.addTarget(self, action:#selector(self.didItemClick(item:))  , for: UIControlEvents.touchUpInside)
            //默認點擊第一個,即首頁
            if i == 0 {
                self .didItemClick(item: itemView)
            }
        }
    }
   
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
   
    //點擊單個標簽視圖纳鼎,通過currentSelectState的屬性觀察器更新標簽item的顯示
    //并且通過代理方法切換標簽控制器的當前視圖控制器
    func didItemClick(item:MainTabBarItem){
        for i in 0..<itemArray.count{
            let tempItem = itemArray[i]
            if i == item.tag{
                tempItem.currentSelectState = true
            }else{
                tempItem.currentSelectState = false
            }
        }
        //執(zhí)行代理方法
        self.delegate?.didChooseItem(itemIndex: item.tag)
    }
}

3.自定義的標簽欄ItemView視圖

class MainTabBarItem: UIControl {
    var itemDic:Dictionary<String, String>
    let imgView: UIImageView
    let titleLabel: UILabel
   
    //屬性觀察器
    var currentSelectState = false {
        didSet{
            if currentSelectState {
                //被選中
                imgView.image = UIImage(named:itemDic["SelectedImg"]!)
                titleLabel.textColor = UIColor.red
            }else{
                //沒被選中
                imgView.image = UIImage(named: itemDic["NormalImg"]!)
                titleLabel.textColor = UIColor.lightGray
            }
        }
    }
   
    init(frame:CGRect, itemDic:Dictionary<String, String>, itemIndex:Int) {
        self.itemDic = itemDic
       
        //布局使用的參數(shù)
        let defaulutLabelH:CGFloat = 20.0 //文字的高度
        var imgTop:CGFloat = 3
        var imgWidth:CGFloat = 25
        //中間的按鈕的布局參數(shù)做特殊處理
        if itemIndex == 1{
            imgTop = -20
            imgWidth = 50
        }
        let imgLeft:CGFloat = (frame.size.width - imgWidth)/2
        let imgHeight:CGFloat  = frame.size.height - defaulutLabelH - imgTop
        //圖片
        imgView = UIImageView(frame: CGRect(x: imgLeft, y: imgTop, width:imgWidth, height:imgHeight))
        imgView.image = UIImage(named: itemDic["NormalImg"]!)
        imgView.contentMode = UIViewContentMode.scaleAspectFit
        //title
        titleLabel = UILabel(frame:CGRect(x: 0, y: frame.height - defaulutLabelH, width: frame.size.width, height: defaulutLabelH))
        titleLabel.text = itemDic["Title"]!
        titleLabel.textAlignment = NSTextAlignment.center
        titleLabel.font = UIFont.systemFont(ofSize: 11)
        titleLabel.textColor = UIColor.lightGray
       
        super.init(frame: frame)
        self.addSubview(imgView)
        self.addSubview(titleLabel)
    }
   
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

第五步:在Appdelegate中設置Window的根視圖控制器為自定義的標簽控制器

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        //創(chuàng)建App窗口
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.backgroundColor = UIColor.orange
        self.window?.makeKeyAndVisible()
        //設置Window的根視圖控制器為自定義的標簽欄
        self.window?.rootViewController = MainTabBarController();
        return true
    }

總結(jié):以上就是在OC代碼的基礎上,使用Swift來自定義標簽控制器的方法和步驟裳凸。在項目前期我們以自定義的方式來創(chuàng)建標簽欄贱鄙,這也是為了后期應對更加復雜的需求做伏筆,比如增加新的控制器我們只需要修改plist配置文件的屬性創(chuàng)建相應的視圖控制器就可以姨谷,這樣就避免了修改大量代碼逗宁。
最后是Demo的鏈接:https://github.com/DreamcoffeeZS/Swift_CustomTabbar.git, 以供參考梦湘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載疙剑,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末践叠,一起剝皮案震驚了整個濱河市言缤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌禁灼,老刑警劉巖管挟,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弄捕,居然都是意外死亡僻孝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門守谓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穿铆,“玉大人,你說我怎么就攤上這事斋荞≤癯” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凤优。 經(jīng)常有香客問我悦陋,道長,這世上最難降的妖魔是什么筑辨? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任俺驶,我火速辦了婚禮,結(jié)果婚禮上棍辕,老公的妹妹穿的比我還像新娘暮现。我一直安慰自己,他們只是感情好楚昭,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布栖袋。 她就那樣靜靜地躺著,像睡著了一般哪替。 火紅的嫁衣襯著肌膚如雪栋荸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天凭舶,我揣著相機與錄音晌块,去河邊找鬼。 笑死帅霜,一個胖子當著我的面吹牛匆背,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播身冀,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼钝尸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搂根?” 一聲冷哼從身側(cè)響起珍促,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剩愧,沒想到半個月后猪叙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡仁卷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年穴翩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锦积。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡芒帕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丰介,到底是詐尸還是另有隱情背蟆,我是刑警寧澤鉴分,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站淆储,受9級特大地震影響冠场,放射性物質(zhì)發(fā)生泄漏家浇。R本人自食惡果不足惜本砰,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钢悲。 院中可真熱鬧点额,春花似錦、人聲如沸莺琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惭等。三九已至珍手,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辞做,已是汗流浹背琳要。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秤茅,地道東北人稚补。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像框喳,于是被迫代替她去往敵國和親课幕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫五垮、插件乍惊、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,066評論 4 62
  • 中國科技企業(yè)已經(jīng)從國內(nèi)市場轉(zhuǎn)向國外擴張匙监,未來西方科技的主導地位面臨挑戰(zhàn)凡橱。 英國倫敦商學院客座教授、牛津大學圣艾德蒙...
    云生活閱讀 305評論 0 0
  • 妻子出差一天亭姥,易見請了一天的病假 易見并不是個工作狂稼钩,對于工作他并沒有多么偏執(zhí)的愛好,只是出于自己對工作和未來的理...
    24e2f6668318閱讀 197評論 0 0
  • 很認真的看完了新聞聯(lián)播静秆,也不知道為啥忽然熱淚盈眶,國家好巡李,人民才好抚笔。其實吧,丫丫一直性格是特別脆弱的侨拦,還是會好好的...
    花兒語樹閱讀 171評論 0 0
  • 今晚在讀季羨林先生《留德十年》中一篇文章《道路終于找到了》,記敘了季先生在德國哥廷根大學選擇自己學習和研究道路的心...
    清源泉閱讀 287評論 0 1