Multitasking card animation in principle

Achieve results


Controls - UICollectionView


The animation is UICollectionViewachieved using a simple speaking under UICollectionViewworks. Here used UICollectionViewit three parts: ViewController(referred to as UICollectionViewCellVC), UICollectionViewLayout, .

  1. ViewController:
    In VC, the UICollectionViewusage with UITableViewsimilar usage. Here initialization method with UITableviewdifferent, more a collectionViewLayoutproperty, each collectionViewwill bind a UICollectionViewLayouttarget, collectionViewaccording to the layoutobject layout cell.

  2. UICollectionViewCell:
    Here used Cellto implement and UITableViewCellno big difference, as long as we realize its initwithFrameinitialization method can then implement the layout you want.

  1. UICollectionViewLayout
    UICollectionViewLayout

UICollectionViewLayoutIs to get UICollectionViewthe essence of the ever-changing, so the focus of the animation above that is layoutin the implementation.
The system provides a UICollectionViewFlowLayout, is a liquid layout, you can set scrollDirectionto specify the scrolling direction, if the layout system provides not meet our needs, then we have to realize own a UICollectionViewLayoutsubclass to achieve the effect we want, and Then referring to the next custom layoutwhich several methods need to be rewritten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

- (void)prepareLayout;

// returns collectionView of contentSize, to determine the scroll range collectionView
- (CGSize) collectionViewContentSize;

// Returns the content offset to use after an animated layout update or change. If you have switched two layout animation, then this method is critical, use it to return to a target contentOffset, can guarantee the normal performance animation.
- (CGPoint) targetContentOffsetForProposedContentOffset: (CGPoint ) proposedContentOffset;

// Returns the layout attributes for all of the cells and views in the specified rectangle.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;

// priority method is used to calculate the specified layout information corresponding indexPath. Here is a layout information UICollectionViewLayoutAttributes object, we can control the state of the cell performance through the frame, center, transform3D, transform. Finally, this attributes object back to the upper layers.
- (UICollectionViewLayoutAttributes *) layoutAttributesForItemAtIndexPath: ( NSIndexPath *) indexPath;

Animated implementation details


The above is about UICollectionViewsome preliminary introduction, there are many details to be using a ruler to explore. Then we said at the implementation details of the animation bar.

The above animation, including displacement, scale, opacity three aspects of change, let's talk about the displacement of some key bar.

Ideas: animated effect, with the sliding finger celldown slowly shift from the displacement process faster and faster; the contrary, if the slip up, cellmoving speed is slowly getting smaller. Here the argument is collectionView.contentOffset.y(the vertical direction), the dependent variable is cell.center.y(or that cell.frame.origin.y), so you need to find a function between them, this function needs to meet the above animation.

According to the law change, first determine a preliminary function:

It is in line with the characteristics of small to large incremental change, you can view images of some online tools to function more intuitive to see the changes of function

You can see that this function is two, then we need only the left part of this, because when we finger decline, collectionView.contentOffset.yin fact, is smaller, but cell.origin.yit is getting bigger, so the change is part of the left half It is what we want.

however

Does not meet the requirements, it needs to be stretched to the right m points ①, ② a tensile n points upward, i.e. to construct a function:

Here explain the meaning of m, the value of n.

will

Make changes in the above two steps, m = 600, n = 500, the following function generates

函数与 x 轴交点是 (600,0),与 y 轴交点是 (0,500)。
(0,500) 比较好理解,就是当 collectionView.contentOffset.y 等于 0 的时候, cell 对应的y坐标为 500。
(600,0) 也不难理解,就是当我们手指往上滑 600 个点,使 collectionView.contentOffset.y=600 时,这个时候 cell.origin.y 会等于 0。

大专栏  多任务卡片动画实现原理eaderlink" title="函数的具体应用">函数的具体应用


定义第 0 个 cell 的位移函数

假设第 0 个 cell(简称 cell0 )对应函数的 m、n 分别为 n0 = 250,m0 = 1000,即当 collectionView.contentOffset.y=0 时, cell0.origin.y=250 ;当我们往上滑1000个点, collectionView.contentOffset.y=1000 时, cell0.origin.y=0 。同理,
ni 则表示当 contentOffset.y=0 时,第 i 个 cell 的 y 坐标。mi 则表示当 contentOffset.y=mi 时,第 i 个 cell 的 y 坐标为 0。

所以对于第 0 个 cell ,我们可以给出一个函数来计算它的 y 坐标:

这里 x 是指 collectionView.contentOffset.y ,y0 是指 cell0.origin.y

生成第 i 个 cell 的位移函数

定义了cell0 的位置函数,就可以以一定规律生成 cell1、cell2…… 的位置函数了,也就是生成每个cell 的 m、n 值。

mi 的计算

我们可以定义,当手指往下滑动140个点时,第1个 cell 会运动到第2个 cell的位置,以此类推,每个 cell 会运动到下一个 cell 的位置。所以我们定义 $m_i=m_{i-1}+140$ 也就是 $m_i=m_0 + itimes140$; (ps:这里140决定了 cell 之间的间距,当然可以根据需求改变这个值来调整视觉效果)

ni 的计算

需要通过 $y_0=((1000-x)/1000)^4times250$ 来计算。我们知道,当 x=0 时,$y_0=n_0=250$。在上一步计算时,我们定义了手指往下滑140时第0个 cell 会运动到第1个 cell 的位置,也就是说 cell1 的位置 $n_1$ 可以由 $y_0=((1000-x)/1000)^4times250$ 得到,这里 x 的值应该是手指从 0 下滑140个点,也就是 collectionView.contentOffset.y=-140 ,所以x=(-140)。(ps:往下滑动时 contentOffset.y 是递减的,所以这里的x是负的140。)所以

同理,可以推出 ni 的公式:

yi 的公式

ok,mi 和ni 都可由 m0、n0 得到,那么 yi 的公式

就可以转化成 m0 和 n0 的表达式,即

虽然这个函数看起来挺长的,但是其中 m0和n0 都是我们定的初始值,140 也是我们定义的常量。变量 x 就是 contentOffset.y 。所以到此我们已经能根据手指的滑动,计算出每个 cell 的 y 坐标,从而实现了这个滚动动画。

公式体现在下面的函数里

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

//根据下标、当前偏移量来获取对应的y坐标
-(CGFloat)getOriginYWithOffsetY:(CGFloat)offsetY row:(NSInteger)row
{
// 公式: y0 = ((m0 - x)/m0)^4*n0
// 公式: yi=((m0 + i*140-x)/(m0 + i*140))^4*((m0+140*i)/m0)^4*n0
CGFloat x = offsetY; //这里offsetY就是自变量x
CGFloat ni = [self defaultYWithRow:row];
CGFloat mi = self.m0+row*self.deltaOffsetY;
CGFloat tmp = mi - x;
tmp = fmaxf(0, tmp); //不小于0
CGFloat y = powf((tmp)/mi, 4)*ni;
// NSLog(@"%d--y:%f ",(int)row,y);
return y;
}

// Get contentOffset.y = 0 when y when the value of each cell is
- (CGFloat) defaultYWithRow: (NSInteger) Row
{
CGFloat X0 = 0 ; // initial state
CGFloat XI = X0 - self.deltaOffsetY * Row;
CGFloat Ni = powf ((self.m0 - XI) /self.m0, . 4 ) * self.n0;
// NSLog (@ "defaultY-% D:% F", (int) Row, Ni); return Ni; }


Transfer from

Guess you like

Origin www.cnblogs.com/lijianming180/p/12037912.html