UICollectionViewFlowLayout實現(xiàn)放大縮小動畫效果的左右滑動

好久沒寫過文章了,趁現(xiàn)在得空寫一下最近實現(xiàn)的UICollectionViewFlowLayout實現(xiàn)的左右滑動功能译荞,先上效果圖:

左右滑動效果

注:這里的分頁方式是使用UIScrollView的setContentOffset方法來實現(xiàn)的,動畫效果上感覺原生的分頁好休弃,但是我不懂如何用pageEnable或其他更好的方法實現(xiàn)由三個cell顯示在屏幕的分頁(剛好能使一個在屏幕正中央)吞歼,如果有朋友有更好的實現(xiàn)方式或者有用過現(xiàn)成的框架,請記得告訴我一下塔猾,謝謝篙骡!

  1. 首先我在StoryBoard里面設(shè)置UICollectionView的約束,設(shè)置距離左邊和右邊都是0,高度隨著我這邊自定義的TopView和BottomView改變

  2. 設(shè)置UICollectionViewCell的Size

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        let sizeWidth = WIDTH - 84
        let sizeHeight = collectionView.bounds.size.height
        return CGSizeMake(sizeWidth, sizeHeight)
    }

這里我設(shè)置UICollectionViewCell的尺寸是距離左右分別是42糯俗,然后高度和UICollectionView一樣高

  1. 自定義的UICollectionViewFlowLayout
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.itemSize = CGSizeMake(itemWidth, itemHeight)
        self.scrollDirection = .Horizontal
        self.minimumLineSpacing = 6
    }

首先設(shè)置UICollectionView的滾動方向以及Cell之間的最小間距尿褪,在這里我設(shè)置為6是因為視覺感官上左右兩邊的Cell不至于相差太遠,在這里我放兩張對比吧叶骨,不縮小和縮小過的圖:

間距為6縮小之后的UICollectionViewCell

間距為6沒有變化的UICollectionViewCell

繼續(xù)實現(xiàn)UICollectionViewFlowLayout里面的方法

    // 布局
    override func prepareLayout() {
        // scrollRate
        collectionView?.decelerationRate = UIScrollViewDecelerationRateNormal
        collectionView?.contentInset = UIEdgeInsets.init(top: 0, left: collectionView!.bounds.width / 2 - (WIDTH - 84) / 2, bottom: 0, right: collectionView!.bounds.width / 2 - (WIDTH - 84) / 2)
    }

在這里設(shè)置了UICollectionView的contentInset茫多,設(shè)置了第一個cell和最后一個cell距離左邊和右邊距離,剛好讓第一個cell和最后一個cell位于最屏幕最中間

    // 邊界改變就重新布局忽刽,默認是false
    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        return true
    }

這個方法表示只要顯示的邊界發(fā)生改變就重新布局(默認是false)

    // 返回所有的UICollectionViewLayoutAttributes
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let array = super.layoutAttributesForElementsInRect(rect)
        // 可見矩陣
        let visiableRect = CGRectMake(self.collectionView!.contentOffset.x, self.collectionView!.contentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)
        for attributes in array! {
            // 不在可見區(qū)域的attributes不變化
            if !CGRectIntersectsRect(visiableRect, attributes.frame) {continue}
            let frame = attributes.frame
            let distance = abs(collectionView!.contentOffset.x + collectionView!.contentInset.left - frame.origin.x)
            let scale = min(max(1 - distance/(collectionView!.bounds.width), 0.85), 1)
            attributes.transform = CGAffineTransformMakeScale(scale, scale)
        }
        return array
    }

這個方法首先取到所有的UICollectionViewLayoutAttributes然后對其進行放大縮小操作天揖。
visiableRect是當前屏幕的Rect,結(jié)合CGRectIntersectsRect方法來判斷哪些cell顯示在屏幕跪帝,好讓我們對其進行操作
distance其實就是計算左邊或者右邊的距離今膊,如果剛好在那個位置(就是cell在中心)的時候,cell就最大
最后就是transform變大變小了
如果這里有些不懂的話伞剑,可以去看看這篇文章:
How to Create an iOS Book Open Animation: Part 1
這里多說一個方法斑唬,如果想連續(xù)滑動幾個Cell的話,不設(shè)置分頁功能的話黎泣,可以再加這個方法恕刘,這個方法是滑動的時候始終讓一個Cell保持在屏幕正中央

    // 當停止滑動,時刻有一張圖片是位于屏幕最中央的抒倚。
    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        let lastRect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)
        //獲得collectionVIew中央的X值(即顯示在屏幕中央的X)
        let centerX = proposedContentOffset.x + self.collectionView!.frame.width * 0.5;
        //這個范圍內(nèi)所有的屬性
        let array = self.layoutAttributesForElementsInRect(lastRect)
        //需要移動的距離
        var adjustOffsetX = CGFloat(MAXFLOAT);
        for attri in array! {
            if abs(attri.center.x - centerX) < abs(adjustOffsetX) {
                adjustOffsetX = attri.center.x - centerX;
            }
        }  
        return CGPointMake((proposedContentOffset.x + adjustOffsetX), proposedContentOffset.y)
    }
  1. 說完了UICollectionViewFlowLayout褐着,我們要簡單模仿分頁的功能(滑動效果感官上不如系統(tǒng)的分頁)
    func scrollViewDidScroll(scrollView: UIScrollView) {
        if self.lastContentOffset < scrollView.contentOffset.x {
            self.scrollToRight = true
        }
        else{
            self.scrollToRight = false
        }
        self.lastContentOffset = scrollView.contentOffset.x
    }

這里主要是判斷向哪邊移動

    private var scrollDistance: CGFloat = WIDTH - 84 + 6
    func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {
        if self.scrollToRight {
            // 向右移動
            let currentCount = Int(scrollView.contentOffset.x/self.scrollDistance) + 1
            if currentCount == 1 {
                let totalScrollDistance = self.scrollDistance - self.collection.contentInset.left
                scrollView.setContentOffset(CGPointMake(CGFloat(currentCount)*totalScrollDistance, 0), animated: true)
            }
            else if currentCount < self.vms.count && currentCount > 1 {
                let totalScrollDistance = CGFloat(currentCount)*self.scrollDistance - self.collection.contentInset.left
                scrollView.setContentOffset(CGPointMake(totalScrollDistance, 0), animated: true)
            }
            else{
                let totalScrollDistance = CGFloat(self.vms.count - 1)*self.scrollDistance - self.collection.contentInset.left
                scrollView.setContentOffset(CGPointMake(totalScrollDistance, 0), animated: true)
            }
        }
        else {
            // 向左移動
            let currentCount = Int(scrollView.contentOffset.x/self.scrollDistance)
            let totalScrollDistance = CGFloat(currentCount)*self.scrollDistance - self.collection.contentInset.left
            scrollView.setContentOffset(CGPointMake(totalScrollDistance, 0), animated: true)
        }
    }

scrollDistance:代表一個Cell的width和Cell間距的和
這里有一個值注意的點:
移動第一個cell的時候,只需要移動scrollDistance減去contentInset.left的距離托呕,因為contentInset.left的距離不計算在scrollView.contentOffset.x里面
移動第一個之外的cell的話含蓉,就是要移動一個scrollDistance的距離了

    func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
        let cell = self.collection.cellForItemAtIndexPath(NSIndexPath.init(forItem: self.currentRow, inSection: 0)) as? XXCell
        cell?.timer?.invalidate()
        
        // compute currentRow
        let distanceWithoutFirstRow = scrollView.contentOffset.x - (self.scrollDistance - self.collection.contentInset.left)
        if distanceWithoutFirstRow < 0 {
            self.currentRow = 0
        }
        else{
            self.currentRow = Int(distanceWithoutFirstRow/self.scrollDistance) + 1
        }
        self.loadBottomView(self.currentRow)
    }

這個是滑動結(jié)束之后調(diào)用的方法,好像是使用了scrollView.setContentOffset才會調(diào)用這個方法
這里我們要計算當前顯示在中央的是哪一個Cell项郊,然后再更新與之對應(yīng)的BottomView的內(nèi)容馅扣。

實現(xiàn)方式差不多就是這樣了,寫個文章記錄一下着降!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末差油,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鹊碍,更是在濱河造成了極大的恐慌厌殉,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侈咕,死亡現(xiàn)場離奇詭異公罕,居然都是意外死亡,警方通過查閱死者的電腦和手機耀销,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門楼眷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铲汪,“玉大人,你說我怎么就攤上這事罐柳≌蒲” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵张吉,是天一觀的道長齿梁。 經(jīng)常有香客問我,道長肮蛹,這世上最難降的妖魔是什么勺择? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮伦忠,結(jié)果婚禮上省核,老公的妹妹穿的比我還像新娘。我一直安慰自己昆码,他們只是感情好气忠,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赋咽,像睡著了一般旧噪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脓匿,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天舌菜,我揣著相機與錄音,去河邊找鬼亦镶。 笑死,一個胖子當著我的面吹牛袱瓮,可吹牛的內(nèi)容都是我干的缤骨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼尺借,長吁一口氣:“原來是場噩夢啊……” “哼绊起!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燎斩,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤虱歪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后栅表,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笋鄙,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年怪瓶,在試婚紗的時候發(fā)現(xiàn)自己被綠了萧落。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖找岖,靈堂內(nèi)的尸體忽然破棺而出陨倡,到底是詐尸還是另有隱情,我是刑警寧澤许布,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布兴革,位于F島的核電站,受9級特大地震影響蜜唾,放射性物質(zhì)發(fā)生泄漏杂曲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一灵妨、第九天 我趴在偏房一處隱蔽的房頂上張望解阅。 院中可真熱鬧,春花似錦泌霍、人聲如沸货抄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟹地。三九已至,卻和暖如春藤为,著一層夾襖步出監(jiān)牢的瞬間怪与,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工缅疟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留分别,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓存淫,卻偏偏與公主長得像耘斩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子桅咆,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

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