CollectionView缩放水平卡片布局

概述

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

前一篇中讲了如何实现CollectionView旋转水平卡片布局,如果还没有阅读过,不防先看看再继续往下阅读。

实现效果

实现思路

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

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

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

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

1

2

3

 

scale = 1 + scaleFactor * (1 - fabs(scaleForDistance))

 

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

核心代码

1

2

3

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;

}

 

实现pagingEnabled的样式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

 

- (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,表示要滚动到下一个。所以在不分页的情况下,其实也是非常简单的。

结尾

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

时间: 2024-10-30 14:53:56

CollectionView缩放水平卡片布局的相关文章

CollectionView旋转水平卡片布局

概述 UICollectionView真的好强大,今天我们来研究一下这种很常见的卡片动画效果是如何实现了.本篇不能太深入地讲解,因为笔者也是刚刚摸索出点眉目,但是并没有深刻地理解.如果在讲解过程中,出现不对的地方,请及时反馈. 效果图 重写API 1 2 3 4 5 6 7 8 9 10 11 12   // 我们必须重写此方法,指定布局大小 // 每次layout invalidated或者重新query布局信息时,会调用 - (void)prepareLayout;   // 用于决定布局信

CollectionView垂直缩放卡片布局

概述 突然想起小美到家App中的一个列表效果,反正正好最近在研究collectonview,正在拿它个效果来练练手.今天教大家如何实现竖直滚动的列表缩放式效果,体验果然提高了不少. 实现效果 缘由 10个月前的事了,那时候在一个很小的创业公司里做美容O2O的,然后研究了很多同行的App,看着人家的效果却不知如何入手,只怪当初太菜. 利用周末研究了一下,果然还是实现出来了.哈哈,时隔这么久还是不能忘记这份"耻辱"啊.不过上周末可不只是实现了这种效果哦,还有好几种效果的.大家可以看文章末尾

Android编程重写ViewGroup实现卡片布局的方法_Android

本文实例讲述了Android编程重写ViewGroup实现卡片布局的方法.分享给大家供大家参考,具体如下: 实现效果如图: 实现思路 1. 重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)设置每个子View的大小 2. 重写onLayout(boolean changed, int l, int t, int r, int b) 设置每个子View的位置 第一步:新建FlowLayout继承ViewGroup package com

关于java卡片布局管理器

问题描述 下面是关于卡片布局管理器,虽然代码没问题,只是有些地方不是太懂,望高手指点,plCenter.add(newButton("One"),"1");plCenter.add(newButton("two"),"2");plCenter.add(newButton("three"),"3");plCenter.add(newButton("four"),&quo

这个卡片布局到底哪儿错了啊

问题描述 红色出我报错的地方,我不知道哪里出错了,还请大家多多指教啊!!!packageStudies;importjava.awt.*;importjava.awt.event.ActionListener;importjavax.swing.*;publicclassCardLayoutTsetextendsPanelimplementsActionListener{PanelcardPanel=newPanel();//创建一个Panel对象CardLayoutc=newCardLayou

Android编程重写ViewGroup实现卡片布局的方法

本文实例讲述了Android编程重写ViewGroup实现卡片布局的方法.分享给大家供大家参考,具体如下: 实现效果如图: 实现思路 1. 重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)设置每个子View的大小 2. 重写onLayout(boolean changed, int l, int t, int r, int b) 设置每个子View的位置 第一步:新建FlowLayout继承ViewGroup package com

Qt之水平/垂直布局(QBoxLayout、QHBoxLayout、QVBoxLayout)

简述 QBoxLayout可以在水平方向或垂直方向上排列控件,由QHBoxLayout.QVBoxLayout所继承. QHBoxLayout:水平布局,在水平方向上排列控件,即:左右排列. QVBoxLayout:垂直布局,在垂直方向上排列控件,即:上下排列. 通过查看源码,我们可以发现,水平布局.垂直布局除了构造时的方向(LeftToRight.TopToBottom)不同外,其它均相同. 下面我们以QHBoxLayout为例,来讲解QBoxLayout的常用功能. 简述 使用 效果 源码

一句话知识:如何解决winform自动缩放产生的布局问题.

Code转自http://www.cnblogs.com/KenBlove/articles/1281823.html有时候你会发现本来好好的WinForm程序在别的机器上显示的尺寸就不对了.这些问题主要发生在背景图片.图片框.窗口布局上.那么那就很可能是因为WinForm的自动放缩功能. 因为不同语言的系统使用不同的缺省字体,相同字体的系统也可能使用不同的DPI(字符的每英寸点数),传统的Win32程序在不同的系统上经常遇到文本显示不全的问题..NET的WinForm提供了自动放缩的功能来试图

AndroidUI设计之 布局管理器 - 详细解析布局实现

写完博客的总结 : 以前没有弄清楚的概念清晰化 父容器与本容器属性 : android_layout...属性是本容器的属性, 定义在这个布局管理器的LayoutParams内部类中, 每个布局管理器都有一个LayoutParams内部类, android:... 是父容器用来控制子组件的属性. 如android:layout_gravity 是控制组件本身的对齐方式, android:gravity是控制本容器子组件的对齐方式; . 作者 :万境绝尘  转载请注明出处 : http://blo