UICollectionView為每一個section分區(qū)設置背景圖片或顏色

《代碼地址》

截屏2020-07-16 下午3.27.12.png
  • 一些應用需要如圖所示一樣在集合視圖上讓不同分區(qū)配置背景圖片或顏色。并且背景要占據分區(qū)頭的高度之類操作,尤其是電商平臺類別的應用窍蓝。但是集合視圖本身不支持直接設置背景圖片郊艘,經過一番研究膘掰,可以通過重寫UICollectionViewFlowLayout實現這個效果洁段。


    IMG_0736.JPG
  • 自定義UICollectionReusableView類晌柬,用來注冊section裝飾背景View

class SectionBackgroundReusableView: UICollectionReusableView {

    static let BACKGAROUND_CID = "BACKGAROUND_CID"
    
    private lazy var bg_imageView = UIImageView().then {
        addSubview($0)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
    }

    override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
        super.apply(layoutAttributes)
        bg_imageView.frame = bounds
        guard let att = layoutAttributes as? SectionDecorationViewCollectionViewLayoutAttributes else {
            return
        }
        self.backgroundColor = UIColor.clear
        bg_imageView.layer.cornerRadius = 5
        bg_imageView.clipsToBounds = true
        bg_imageView.backgroundColor = att.backgroundColor
        guard let imageName = att.imageName else {
            self.bg_imageView.image = nil
            return
        }
        guard let image_url = URL(string: imageName) else {
            return
        }
        self.bg_imageView.kf.setImage(with: image_url)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
  • 自定義UICollectionViewLayoutAttributes,用來保存section的背景圖片和顏色數據
class SectionDecorationViewCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
    
    // 裝飾背景圖片
    var imageName: String?
    // 背景色
    var backgroundColor = UIColor.white

    /// 所定義屬性的類型需要遵從 NSCopying 協(xié)議
    /// - Parameter zone:
    /// - Returns:
    override func copy(with zone: NSZone? = nil) -> Any {
        let copy = super.copy(with: zone) as! SectionDecorationViewCollectionViewLayoutAttributes
        copy.imageName = self.imageName
        copy.backgroundColor = self.backgroundColor
        return copy
    }
    
    /// 所定義屬性的類型還要實現相等判斷方法(isEqual)
    /// - Parameter object:
    /// - Returns: 是否相等
    override func isEqual(_ object: Any?) -> Bool {
        guard let rhs = object as? SectionDecorationViewCollectionViewLayoutAttributes else {
            return false
        }
        if self.imageName != rhs.imageName {
            return false
        }
        if !self.backgroundColor.isEqual(rhs.backgroundColor) {
            return false
        }
        return super.isEqual(object)
    }
}

  • 自定義UICollectionViewFlowLayout類
  1. 先注冊背景View
    override init() {
        super.init()
        // 背景View注冊
        self.register(SectionBackgroundReusableView.self, forDecorationViewOfKind: SectionBackgroundReusableView.BACKGAROUND_CID)
    }
  1. 設置背景的位置和大小
    // 布局配置數據
    override func prepare() {
        super.prepare()
        // 如果collectionView當前沒有分區(qū)垒探,則直接退出
        guard let numberOfSections = self.collectionView?.numberOfSections
            else {
                return
        }
        // 不存在cardDecorationDelegate就退出
        guard let delegate = decorationDelegate else {
            return
        }
        if decorationBackgroundAttrs.count > 0 {
            decorationBackgroundAttrs.removeAll()
        }
        for section:Int in 0..<numberOfSections {
            // 獲取該section下第一個妓蛮,以及最后一個item的布局屬性
            guard let numberOfItems = self.collectionView?.numberOfItems(inSection: section),
                numberOfItems > 0,
                let firstItem = self.layoutAttributesForItem(at:
                    IndexPath(item: 0, section: section)),
                let lastItem = self.layoutAttributesForItem(at:
                    IndexPath(item: numberOfItems - 1, section: section))
                else {
                    continue
            }
            var sectionInset:UIEdgeInsets = self.sectionInset
            /// 獲取該section的內邊距
            let inset:UIEdgeInsets = delegate.collectionView(collectionView: self.collectionView!, layout: self, insetForSectionAt: section)
            if !(inset == .zero) {
                sectionInset = inset
            }
            
            /// 獲取該section header的size
            let headerSize = delegate.collectionView(collectionView: self.collectionView!, layout: self, headerForSectionAt: section)
            var sectionFrame:CGRect = .zero
            if self.scrollDirection == .horizontal {
                let hx = (firstItem.frame.origin.x) - headerSize.width + sectionInset.left
                let hy = (firstItem.frame.origin.y) + sectionInset.top
                let hw = ((lastItem.frame.origin.x) + (lastItem.frame.size.width)) - sectionInset.right
                let hh = ((lastItem.frame.origin.y) + (lastItem.frame.size.height)) - sectionInset.bottom
                sectionFrame = CGRect(x:  hx , y: hy, width: hw, height: hh)
                sectionFrame.origin.y = sectionInset.top
                sectionFrame.size.width = sectionFrame.size.width-sectionFrame.origin.x
                sectionFrame.size.height = self.collectionView!.frame.size.height - sectionInset.top - sectionInset.bottom
                
            } else {
                let vx = (firstItem.frame.origin.x)
                let vy = (firstItem.frame.origin.y) - headerSize.height + sectionInset.top
                let vw = ((lastItem.frame.origin.x) + (lastItem.frame.size.width))
                let vh = ( (lastItem.frame.origin.y) + (lastItem.frame.size.height) ) - sectionInset.bottom
                sectionFrame = CGRect(x:  vx , y: vy, width: vw, height: vh + 10)
                sectionFrame.origin.x = sectionInset.left
                sectionFrame.size.width = (self.collectionView?.frame.size.width)! - sectionInset.left - sectionInset.right
                sectionFrame.size.height = sectionFrame.size.height - sectionFrame.origin.y
            }
            
            let attrs = SectionDecorationViewCollectionViewLayoutAttributes(forDecorationViewOfKind: SectionBackgroundReusableView.BACKGAROUND_CID, with: IndexPath(item: 0, section: section))
            let backgroundColor = delegate.collectionView(self.collectionView!, layout: self, decorationColorForSectionAt: section)
            attrs.frame = sectionFrame
            attrs.zIndex = -1
            attrs.backgroundColor = backgroundColor
            /// 優(yōu)先保存顏色
            self.decorationBackgroundAttrs[section] = attrs
            
            /// 判斷背景圖片是否可見 不可見跳過
            let backgroundDisplayed = delegate.collectionView(self.collectionView!, layout: self, decorationImgaeDisplayedForSectionAt: section)
            guard backgroundDisplayed == true else {
                continue
            }
            ///  如果背景圖片名稱為nil怠李,跳過
            guard let imageName = delegate.collectionView(self.collectionView!, layout: self, decorationImageForSectionAt: section) else {
                continue
            }
            attrs.imageName = imageName
            
            
            let displayedFillet = delegate.collectionView(self.collectionView!, layout: self, filletDisplayedForSectionAt: section)
            guard displayedFillet == false else {
                continue
            }
            // 將該section的布局屬性保存起來
            self.decorationBackgroundAttrs[section] = attrs
        }
        
    }
  1. 這個方法比較重要圾叼,collectionView的分區(qū)可以設置背景這是重點,重寫DecorationView捺癞。Decoration View是UICollectionView的裝飾視圖夷蚊,這是蘋果官方解釋,
    // If the layout supports any supplementary or decoration view types, it should also implement the respective atIndexPath: methods for those types.
    //如果布局支持任何補充或裝飾視圖類型髓介,則還應該為這些類型實現相應的atIndexPath:方法惕鼓。
    override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let section = indexPath.section
        if elementKind  == SectionBackgroundReusableView.BACKGAROUND_CID {
            return self.decorationBackgroundAttrs[section]
        }
        return super.layoutAttributesForDecorationView(ofKind: elementKind,
                                                       at: indexPath)
    }
  1. 重要的代碼都做了解釋,如果剛好需要這個效果的唐础,可以下載代碼看看箱歧,再結合自身的需求進行修改矾飞。代碼地址在前面已經貼出來了


    7a65dbe6e060de7e6629c85b06e4c82c.jpg
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市呀邢,隨后出現的幾起案子洒沦,更是在濱河造成了極大的恐慌,老刑警劉巖价淌,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件申眼,死亡現場離奇詭異,居然都是意外死亡蝉衣,警方通過查閱死者的電腦和手機括尸,發(fā)現死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來病毡,“玉大人濒翻,你說我怎么就攤上這事±材ぃ” “怎么了肴焊?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長功戚。 經常有香客問我娶眷,道長,這世上最難降的妖魔是什么啸臀? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任届宠,我火速辦了婚禮,結果婚禮上乘粒,老公的妹妹穿的比我還像新娘豌注。我一直安慰自己,他們只是感情好灯萍,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布轧铁。 她就那樣靜靜地躺著,像睡著了一般旦棉。 火紅的嫁衣襯著肌膚如雪齿风。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天绑洛,我揣著相機與錄音救斑,去河邊找鬼。 笑死真屯,一個胖子當著我的面吹牛脸候,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼运沦,長吁一口氣:“原來是場噩夢啊……” “哼泵额!你這毒婦竟也來了?” 一聲冷哼從身側響起携添,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤梯刚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后薪寓,有當地人在樹林里發(fā)現了一具尸體亡资,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年向叉,在試婚紗的時候發(fā)現自己被綠了锥腻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡母谎,死狀恐怖瘦黑,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情奇唤,我是刑警寧澤幸斥,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站咬扇,受9級特大地震影響甲葬,放射性物質發(fā)生泄漏。R本人自食惡果不足惜懈贺,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一经窖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧梭灿,春花似錦画侣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皮迟,卻和暖如春搬泥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背万栅。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工佑钾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烦粒。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扰她。 傳聞我的和親對象是個殘疾皇子兽掰,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345