天天看点

CollectionView缩放水平卡片布局概述实现效果实现思路核心代码实现pagingEnabled的样式感谢结尾

本篇一起来学习如何使用uicollectionview来实现水平滚动的缩放式卡片布局,就像nice app中的卡片布局。

CollectionView缩放水平卡片布局概述实现效果实现思路核心代码实现pagingEnabled的样式感谢结尾

从demo效果图中,可以看出来,主要是缩放系数的计算。对于不同距离的cell,其缩放系数要变化,以便整体协调显示。

所以,我们必须重写-layoutattributesforelementsinrect:方法来实现所有当前可见的cell的attributes。

计算比例,通过获取当前偏移rect的最小坐标x,再与atribute的中心x相减,再除以高度,就是高度的缩放倍数scalefordistance。

最后,通过一个公式来计算缩放的y系数。公式为:

1

2

3

scale = 1 + scalefactor * (1 - fabs(scalefordistance))

scalefactor因子可以自由调整,值越大,显示就越大。

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

#pragma mark - override

- (void)preparelayout {

  self.scrolldirection = uicollectionviewscrolldirectionhorizontal;

  self.minimumlinespacing = 20;

  //  self.minimuminteritemspacing = 20;

  self.sectioninset = uiedgeinsetsmake(0, 30, 0, 30);

  self.itemsize = cgsizemake(self.collectionview.frame.size.width - 60,

                             self.collectionview.frame.size.height - 180);

  [super preparelayout];

}

- (bool)shouldinvalidatelayoutforboundschange:(cgrect)newbounds {

  return yes;

- (nsarray<uicollectionviewlayoutattributes *> *)layoutattributesforelementsinrect:(cgrect)rect {

  nsarray *superattributes = [super layoutattributesforelementsinrect:rect];

  nsarray *attributes = [[nsarray alloc] initwitharray:superattributes copyitems:yes];

  cgrect visiblerect = cgrectmake(self.collectionview.contentoffset.x,

                                  self.collectionview.contentoffset.y,

                                  self.collectionview.frame.size.width,

                                  self.collectionview.frame.size.height);

  cgfloat offset = cgrectgetmidx(visiblerect);

  [attributes enumerateobjectsusingblock:^(uicollectionviewlayoutattributes *attribute, nsuinteger idx, bool * _nonnull stop) {

    cgfloat distance = offset - attribute.center.x;

    // 越往中心移动,值越小,那么缩放就越小,从而显示就越大

    // 同样,超过中心后,越往左、右走,缩放就越大,显示就越小

    cgfloat scalefordistance = distance / self.itemsize.height;

    // 0.2可调整,值越大,显示就越大

    cgfloat scaleforcell = 1 + 0.2 * (1 - fabs(scalefordistance));

    // only scale y-axis

    attribute.transform3d = catransform3dmakescale(1, scaleforcell, 1);

    attribute.zindex = 1;

  }];

  return attributes;

- (cgpoint)targetcontentoffsetforproposedcontentoffset:(cgpoint)proposedcontentoffset withscrollingvelocity:(cgpoint)velocity {

  bool pagingenabled = no;

  if (pagingenabled) {

    // 分页以1/3处

    if (proposedcontentoffset.x > self.previousoffsetx + self.itemsize.width / 3.0) {

      self.previousoffsetx += self.collectionview.frame.size.width - self.minimumlinespacing * 2;

    } else if (proposedcontentoffset.x < self.previousoffsetx  - self.itemsize.width / 3.0) {

      self.previousoffsetx -= self.collectionview.frame.size.width - self.minimumlinespacing * 2;

    }

    proposedcontentoffset.x = self.previousoffsetx;

  } else {

    cgfloat x = proposedcontentoffset.x / (self.itemsize.width + self.minimumlinespacing);

    int base = (int)x;

    proposedcontentoffset.x = base * (self.itemsize.width + self.minimumlinespacing);

  }

  return proposedcontentoffset;

这里是以1/3.0为分界,左、右的1/3作为分界线,超过才会切换过去!

感谢评论的朋友们的一句话,点醒了笔者。对于不分页的情况下,其实只要使用当前的偏移x除(itemsize.width + minimumlinespacing)就得到一个倍数,然后四舍五入。比如,4.3取整得到4,那么就是没有超过一半,就要往回滚。而4.6取整得到5,表示要滚动到下一个。所以在不分页的情况下,其实也是非常简单的。

本篇文章经过朋友们的评论及反馈,可以说已经完善了!