iOS- 用Swift寫(xiě)的一個(gè)標(biāo)題選項(xiàng)卡控件

學(xué)習(xí)Swift之后這個(gè)控件寫(xiě)了很久了. 但是把這個(gè)框架做成pod集成到項(xiàng)目中的時(shí)候發(fā)現(xiàn)因?yàn)榭丶暮诵念悰](méi)有聲明"public"而導(dǎo)致無(wú)法訪問(wèn). 在把class 前聲明為Public后又有一堆協(xié)議方法也需要修改訪問(wèn)權(quán)限..(這個(gè)比OC有點(diǎn)麻煩了)

順便整理記錄一下這個(gè)框架吧
git: [https://github.com/Zafirzzf/ZFPageTitleView]

 /// 構(gòu)造函數(shù)
    ///
    /// - Parameters:
    ///   - frame: 包含自控制器的整個(gè)frame
    ///   - titles: 標(biāo)題數(shù)組
    ///   - childControllers: 內(nèi)容控制器數(shù)組
    ///   - parentVC: 裝此控件的控制器
    ///   - style: 界面主題色
   public init(frame: CGRect, titles: [String], childControllers: [UIViewController], parentVC: UIViewController,style: ZFPageStyle = ZFPageStyle()) {

        self.titleStyle = style
        self.titles = titles
        self.childControllers = childControllers
        self.parentVC = parentVC
        parentVC.automaticallyAdjustsScrollViewInsets = false
        super.init(frame: frame)
        setupUI()
        
    }

在接收到最需要的標(biāo)題數(shù)組和子控制器數(shù)組之后,創(chuàng)建標(biāo)題視圖,并用collectionView展示子控制器里的view.

  fileprivate func setupUI() {
        // title
        let titleView = ZFTitleView(frame: CGRect(x: 0, y: 0, width: bounds.width,
                                    height: titleStyle.titleViewHeight),
                                    style: titleStyle,
                                    titles: titles)
        addSubview(titleView)
        
        //內(nèi)容
        let contentFrame = CGRect(x: 0, y: titleView.frame.maxY, width: bounds.width, height: bounds.height - titleView.frame.height)
        let contentView = ZFContentView(frame:contentFrame,
                                        childControllers: childControllers,
                                        parentVC: parentVC)
        contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        addSubview(contentView)
        
        //設(shè)置標(biāo)題view和內(nèi)容視圖的關(guān)系
        titleView.delegage = contentView
        contentView.delegate = titleView
    }

ZFTitleViewZFContentView是抽離出來(lái)的兩個(gè)類.分別控制標(biāo)題視圖與內(nèi)容.titleView于contentView之間的事件交互利用代理完成很方便.

TitleView上根據(jù)標(biāo)題的數(shù)量創(chuàng)建N個(gè)Button添加到scrollView上,根據(jù)標(biāo)題的總長(zhǎng)度調(diào)整位置即可.

在滑動(dòng)下方contentView的時(shí)候上方標(biāo)題視圖中的當(dāng)前選中文字與將要選中的文字有一個(gè)漸變的顏色變化.處理方式如下:

   public func contentView(_ contentView: ZFContentView, targetIndex: Int, progress: CGFloat) {

        if progress > 0.9 {
            selectIndex = targetIndex
            //調(diào)整位置
            setScrollInset(titleLabels[selectIndex])
        }
        
        let fonttransformScale = style.fontTransformScale
        let oldLabelScale = fonttransformScale - (fonttransformScale - 1) * progress
        let targetLabelScale = 1 + (fonttransformScale - 1) * progress
        let oldLabel = titleLabels[selectIndex]
        let newLabel = titleLabels[targetIndex]
        
        // 滑動(dòng)過(guò)程中縮放字體
        oldLabel.transformScale(scale: oldLabelScale)
        newLabel.transformScale(scale: targetLabelScale)
        
        // 改變字體顏色
        let normalColor = getRGBValue(style.textNormalColor)
        let selectColor = getRGBValue(style.textSelectColor)
        let excessColor = (selectColor.0 - normalColor.0,
                           selectColor.1 - normalColor.1,
                           selectColor.2 - normalColor.2)
        
        oldLabel.textColor = UIColor(red: (selectColor.0 - excessColor.0 * progress) / 255.0,
                                     green: (selectColor.1 - excessColor.1 * progress) / 255.0,
                                     blue: (selectColor.2 - excessColor.2 * progress) / 255.0,
                                     alpha: 1)
        newLabel.textColor = UIColor(red: (normalColor.0 + excessColor.0 * progress) / 255.0,
                                     green: (normalColor.1 + excessColor.1 * progress) / 255.0,
                                     blue: (normalColor.2 + excessColor.2 * progress) / 255.0,
                                     alpha: 1)
    }



 func getRGBValue(_ color: UIColor) ->(CGFloat,CGFloat,CGFloat) {
        guard let components = color.cgColor.components else {
            fatalError("文字顏色請(qǐng)按照RGB設(shè)置")
        }
        return (components[0] * 255, components[1] * 255, components[2] * 255)
    }

核心步驟是:

  1. 獲取normalcolor和selectcolor的兩個(gè)RGB值.
  2. 兩個(gè)值的R,G,B相減獲取到過(guò)度的一個(gè)顏色值.
  3. 根據(jù)當(dāng)前滑動(dòng)的進(jìn)度progress,使normalcolor和selectcolor向過(guò)度值進(jìn)行過(guò)度
    注: 這種方法要確保Color.cgColor.components有值,所以兩種顏色需要通過(guò)RGB進(jìn)行設(shè)置.其它方法設(shè)置的會(huì)獲取不到RGB值.

如果想要加上滑動(dòng)過(guò)程中sel的標(biāo)題進(jìn)行縮放,同理根據(jù)progress操作.

contentView里有一個(gè)左右滑動(dòng)的collectionView,它的cell就是childControllers里的每個(gè)控制器的view.這樣在控制器比較多的情況下可以讓view之間復(fù)用.比ScrollView會(huì)節(jié)省內(nèi)存的占用.

需要注意的是為了防止復(fù)用.每次加載新view時(shí)要將之前的刪除.

   public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath)
        // 注意刪除之前cell上的view
        _ = cell.contentView.subviews.map{ $0.removeFromSuperview() }
        
        let childView = childVC[indexPath.item].view!
        childView.frame = cell.contentView.bounds
        cell.contentView.addSubview(childView)
        
        return cell
    }

滑動(dòng)contentView更新titleView的變化通過(guò)scrollView的代理即可.

//MARK:- ScrollView 代理
extension ZFContentView: UICollectionViewDelegate {

    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        
        delegate?.contentView(self, endScroll:Int(scrollView.contentOffset.x / bounds.width))
    }

    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if isForbidDelegate { return }
        
        let offsetX = scrollView.contentOffset.x
        var targetIndex: Int
        var progress: CGFloat = 0
        if offsetX < scrollStartOffSet { //向左滑
            progress = (scrollStartOffSet - offsetX) / bounds.width
            targetIndex = Int(scrollStartOffSet / bounds.width) - 1
            if targetIndex < 0{
                targetIndex = 0
            }
        }else {
            progress = (offsetX - scrollStartOffSet) / bounds.width
            targetIndex = Int(scrollStartOffSet / bounds.width) + 1
            if targetIndex >= childVC.count {
                targetIndex = childVC.count - 1
            }
        }
      
        delegate?.contentView(self, targetIndex: targetIndex, progress: progress)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泳炉,一起剝皮案震驚了整個(gè)濱河市紊服,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殊橙,老刑警劉巖赠幕,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俄精,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榕堰,警方通過(guò)查閱死者的電腦和手機(jī)竖慧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逆屡,“玉大人圾旨,你說(shuō)我怎么就攤上這事∥赫幔” “怎么了砍的?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)莺治。 經(jīng)常有香客問(wèn)我廓鞠,道長(zhǎng),這世上最難降的妖魔是什么谣旁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任床佳,我火速辦了婚禮,結(jié)果婚禮上榄审,老公的妹妹穿的比我還像新娘砌们。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布浪感。 她就那樣靜靜地躺著昔头,像睡著了一般。 火紅的嫁衣襯著肌膚如雪影兽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天赢笨,我揣著相機(jī)與錄音未蝌,去河邊找鬼。 笑死萧吠,一個(gè)胖子當(dāng)著我的面吹牛梅忌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼洲赵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叠萍!你這毒婦竟也來(lái)了俭令?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雾叭,失蹤者是張志新(化名)和其女友劉穎织狐,沒(méi)想到半個(gè)月后厨埋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唉地,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年骚烧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赃绊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碧查。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卦方,靈堂內(nèi)的尸體忽然破棺而出盼砍,到底是詐尸還是另有隱情吗跋,我是刑警寧澤跌宛,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布酗宋,位于F島的核電站,受9級(jí)特大地震影響疆拘,放射性物質(zhì)發(fā)生泄漏蜕猫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一哎迄、第九天 我趴在偏房一處隱蔽的房頂上張望回右。 院中可真熱鬧,春花似錦漱挚、人聲如沸翔烁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹬屹。三九已至,卻和暖如春白华,著一層夾襖步出監(jiān)牢的瞬間慨默,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工弧腥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厦取,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓管搪,卻偏偏與公主長(zhǎng)得像虾攻,于是被迫代替她去往敵國(guó)和親铡买。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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