iOS – 图片实现多叠折叠功能。iOS动画相关笔记。


每当网上能找到好多图折叠功能的课,但多数凡是相同层折叠,在他们的课程的根基及,我碰着实现了一下大多交汇折叠的效能。操作如下~

CALayer的属性

效果


foldImage.gif

1 contents

contents属性用来绘制寄宿图,它承受一个id类型,但是实际接受之凡CGImageRef,一个对CGImage的指针,但是一直以UIImage的CGImage属性是特别的,因为它需要一个cocoa对象要未是CoreFoundation对象,可以下以下措施开转换:

layer.contents = (__bridge id)image.CGImage

Demo


Demo地址:https://github.com/Resory/RYMutipleFoldImageView
假如公共人喜欢的语不妨让个片吧。

2 contentsGravity

contentsGravity属性类似于UIView的contentMode,不过他是一个NSString,有以下值:

kCAGravityCenter
kCAGravityTop
kCAGravityBottom
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
kCAGravityBottomLeft
kCAGravityBottomRight
kCAGravityResize
kCAGravityResizeAspect
kCAGravityResizeAspectFill

逻辑


  • 于召开图片折叠功能的时刻,我们得掌握为将图纸分成几组成部分,然后分别指向各级部分做动效来实现折功能。

  • 据悉动态图,可以看来这是如出一辙张大图”分成”4单稍imageView。从高达至下,我们分别命名也one,two,three,four

  • one,two,three,four这四单稍imageView进行盘+移动。旋转的早晚,关键是看各个imageView的anchorPoint是多少.而我辈这边,可看p1图备受的红点。

    • a1代表one的anchorPoint为(0.5,0.0)
    • a2代表two的anchorPoint为(0.5,1.0)
    • a3代表three的anchorPoint为(0.5,0.0)
    • a4代表four的anchorPoint为(0.5,1.0)

p1.png

  • 旋转:
    • 咱们这边的imageView都是转45°或者是-45°,这个用CATransform3DRotate即可形成。
  • 移动(关键):
  • 转后,各个imageView都见面变形而还同大小,只有职不一致,我们设根据这个旋转后的imageView高度来进行运动。
  • 比如two要和one紧接。根据动态图,one仅生旋转,没有运动。而two则旋转和动了。那么移动了有点为。在从来不折叠前,所有的imageView高度都是50px。也就是是onetwo一共加起是100px。而折叠后。onetwo且更换多少了。就是为她们少只都易多少了。所以中级就是起了缝隙,这个缝隙即便是咱们要运动的离开。而我辈理解当二维空间受到,总长度是100px,one,two的万丈在盘后是可算是出来的,也就是说缝隙的次维空间距离是:100-2*(one.frame.size.height)。,然后再度经过CATransform3DMakeAffineTransform方法的换得到实在地三维空间活动的偏离。

3 contentsScale

斯特性不是为此来装缩放的(缩放有transformaffineTransform),而是同retina屏幕关于,如果设置也1.0虽然1个点来得一个像素,设置为2.0虽说1单点来得两只像素。但是她并无连续实惠,如果你设置了contentsGravitykCAGravityResizeAspect针对图片做了拉伸,那再装contentsScale即没有因此了,但是若你设置为kCAGravityCenter,那便来因此了,一般会这样来设置scale:

layer.contentsScale = [UIScreen mainScreen].scale;

实现


  • ##### 初始化4个小imageView(contentsRect的运用)

- (void)configFourFoldImage
{
    UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(10, 100, 300, IMAGE_PER_HEIGIT*4)];
    [self.view addSubview:bgView];

    // 把kiluya这张图,分成平均分成4个部分的imageview
    _one = [[UIImageView alloc] init];
    _one.image = [UIImage imageNamed:@"Kiluya.jpg"];
    _one.layer.contentsRect = CGRectMake(0, 0, 1, 0.25);
    _one.layer.anchorPoint = CGPointMake(0.5, 0.0);
    _one.frame = CGRectMake(0, 0, 300, IMAGE_PER_HEIGIT);

    _two = [[UIImageView alloc] init];
    _two.image = [UIImage imageNamed:@"Kiluya.jpg"];
    _two.layer.contentsRect = CGRectMake(0, 0.25, 1, 0.25);
    _two.layer.anchorPoint = CGPointMake(0.5, 1.0);
    _two.frame = CGRectMake(0, IMAGE_PER_HEIGIT, 300, IMAGE_PER_HEIGIT);

    _three = [[UIImageView alloc] init];
    _three.image = [UIImage imageNamed:@"Kiluya.jpg"];
    _three.layer.contentsRect = CGRectMake(0, 0.5, 1, 0.25);
    _three.layer.anchorPoint = CGPointMake(0.5, 0.0);
    _three.frame = CGRectMake(0, IMAGE_PER_HEIGIT*2, 300, IMAGE_PER_HEIGIT);

    _four = [[UIImageView alloc] init];
    _four.image = [UIImage imageNamed:@"Kiluya.jpg"];
    _four.layer.contentsRect = CGRectMake(0, 0.75, 1, 0.25);
    _four.layer.anchorPoint = CGPointMake(0.5, 1.0);
    _four.frame = CGRectMake(0, IMAGE_PER_HEIGIT*3, 300, IMAGE_PER_HEIGIT);

    [bgView addSubview:_one];
    [bgView addSubview:_two];
    [bgView addSubview:_three];
    [bgView addSubview:_four];

    // 给第一张和第三张添加阴影
    _oneShadowView = [[UIView alloc] initWithFrame:_one.bounds];
    _oneShadowView.backgroundColor = [UIColor blackColor];
    _oneShadowView.alpha = 0.0;

    _threeShadowView = [[UIView alloc] initWithFrame:_three.bounds];
    _threeShadowView.backgroundColor = [UIColor blackColor];
    _threeShadowView.alpha = 0.0;

    [_one addSubview:_oneShadowView];
    [_three addSubview:_threeShadowView];
}
  • ##### 生成折叠动效需要的CATransform3D

- (CATransform3D)config3DTransformWithRotateAngle:(double)angle andPositionY:(double)y
{
    CATransform3D transform = CATransform3DIdentity;
    // 立体
    transform.m34 = -1/1000.0;
    // 旋转
    CATransform3D rotateTransform = CATransform3DRotate(transform, M_PI*angle/180, 1, 0, 0);
    // 移动(这里的y坐标是平面移动的的距离,我们要把他转换成3D移动的距离.这是关键,没有它,图片就没办法很好地对接。)
    CATransform3D moveTransform = CATransform3DMakeAffineTransform(CGAffineTransformMakeTranslation(0, y));
    // 合并
    CATransform3D concatTransform = CATransform3DConcat(rotateTransform, moveTransform);
    return concatTransform;
}
  • ##### 折叠

// 动效是否执行中
static bool isFolding = NO;

- (IBAction)fold:(id)sender
{
    if(!isFolding)
    {
        isFolding = YES;

        [UIView animateWithDuration:1.0
                              delay:0
             usingSpringWithDamping:1.0
              initialSpringVelocity:0
                            options:UIViewAnimationOptionCurveLinear
                         animations:^{
            // 阴影显示
            _oneShadowView.alpha = 0.2;
            _threeShadowView.alpha = 0.2;

            // 折叠
            _one.layer.transform = [self config3DTransformWithRotateAngle:-45.0
                                                             andPositionY:0];
            _two.layer.transform = [self config3DTransformWithRotateAngle:45.0
                                                             andPositionY:-100+2*_one.frame.size.height];
            _three.layer.transform = [self config3DTransformWithRotateAngle:-45.0
                                                               andPositionY:-100+2*_one.frame.size.height];
            _four.layer.transform = [self config3DTransformWithRotateAngle:45.0
                                                              andPositionY:-200+4*_one.frame.size.height];

        } completion:^(BOOL finished) {

            if(finished)
            {
                isFolding = NO;
            }
        }];
    }
}
  • ##### 恢复

- (IBAction)reset:(id)sender
{
    isFolding = NO;

    [UIView animateWithDuration:1.0
                          delay:0
         usingSpringWithDamping:1.0
          initialSpringVelocity:0
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{

        // 阴影隐藏
        _oneShadowView.alpha = 0.0;
        _threeShadowView.alpha = 0.0;

        // 图片恢复原样
        _one.layer.transform = CATransform3DIdentity;
        _two.layer.transform = CATransform3DIdentity;
        _three.layer.transform = CATransform3DIdentity;
        _four.layer.transform = CATransform3DIdentity;

    } completion:^(BOOL finished) {

    }];
}

4 maskToBounds

UIView有一个clipsToBounds性,用来支配是否出示超过边界的情节,CALayer对应之习性叫做masksToBounds,把其装也YES,图像就未会见盖边界绘制了。


  • 此处最主要是缝隙的精打细算,这个想掌握了。其他就是从来不什么了。

  • 假使您生问题还是发现错误请留言为本人,喜欢就点单赞吧!3Q

1.5 contentsRect

就此来支配显示图像的相同片,CGRect类型,但是利用单位坐标,范围是0~1:

layer.contentsRect = CGRectMake(0,0,0.5,0.5);// 显示图像左上角

5 contentsCenter

暨名字不同,这个特性用来控制拉伸(改变contentsGravity的时)的界定,依旧采用单位坐标,默认值为(0,0,1,1),均匀拉伸,设置任何价值的功力参考下图:

图片 1

contentsCenter效果

    UIView *whiteView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH / 2, SCREEN_WIDTH / 2)];
    whiteView.centerX = SCREEN_WIDTH / 2;
    whiteView.centerY = SCREEN_HEIGHT / 2;
    whiteView.backgroundColor = [UIColor whiteColor];

    UIImage *image = [UIImage imageNamed:@"facecertificate_done"];
    whiteView.layer.contents = (__bridge id)image.CGImage;
    whiteView.layer.contentsGravity = kCAGravityCenter;
    whiteView.layer.contentsScale = [UIScreen mainScreen].scale;
    whiteView.layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);
    whiteView.layer.contentsCenter = CGRectMake(0.25, 0.25, 0.75, 0.75);
    whiteView.layer.contentsGravity = kCAGravityResize;

6 UIView的drawRect方法

使用是点子吗得绘制寄宿图。它没有默认的实现,因为对UIView来说,寄宿图并无是要的,它不在意那究竟是干燥的颜色还是出一个图的实例。如果UIView检测到-drawRect:
方法让调用了,它就会见为视图分配一个寄宿图,这个寄宿图的比如说素尺寸等于视图大小就以
contentsScale的价值。如果您不需寄宿图,那即便无须创建是法了,这会招CPU资源与内存的浪费,这为是干什么苹果建议:如果无于定义绘制的职责就是不用在子类中形容一个拖欠的-drawRect:方法。

7 布局

frame代表了图层的标坐标(也就算是以父图层上占的空间),bounds是中间坐标({0,
0}通常是图层的左上角),center和position都代表了针锋相对于父图层anchorPoint所当的职位。
frame并无是一个老清楚的习性,它实在是一个虚构性,是冲bounds,position和transform计算而来,所以当内任何一个价发生变更,frame都见面变卦。

8 position和anchorPoint

position和anchorPoint没法分开说,position单位是触发,anchorPoint则是一个单位坐标,position是一个针锋相对于父layer的坐标,anchorPoint则是相对于我layer的一个碰,当这个点和position重合的时(anchorPoint向position移动),自身layer的职就规定了。更改layer的里边一个价未会见潜移默化外一个值,但是会影响layer所在的职位。
推选个栗子:

UIView *whiteView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH / 2, SCREEN_WIDTH / 2)];
whiteView.centerX = SCREEN_WIDTH / 2;
whiteView.centerY = SCREEN_HEIGHT / 2;
whiteView.backgroundColor = [UIColor whiteColor];

CALayer *blueLayer = [CALayer layer];
blueLayer.frame = CGRectMake(SCREEN_WIDTH / 8, SCREEN_WIDTH / 8, SCREEN_WIDTH / 4, SCREEN_WIDTH / 4);
blueLayer.backgroundColor = [UIColor blueColor].CGColor;
[whiteView.layer addSublayer:blueLayer];
NSLog(@"sublayer position:(%.2f,%.2f) anchorPoint:(%.2f,%.2f)", blueLayer.position.x, blueLayer.position.y, blueLayer.anchorPoint.x, blueLayer.anchorPoint.y);

如下:

图片 2

未设置.jpg

输出为:

sublayer position:(93.75,93.75) anchorPoint:(0.50,0.50)

这会儿底position为view的中央,锚点为中心点

改变下position

blueLayer.position = CGPointMake(70, 70);

如下:

图片 3

position.PNG

输出为:

sublayer position:(70.00,70.00) anchorPoint:(0.50,0.50)

只改变anchorPoint:

blueLayer.anchorPoint = CGPointMake(0, 0);

如下:

图片 4

anchorPoint.PNG

输出为:

sublayer position:(93.75,93.75) anchorPoint:(0.00,0.00)

9 zPosition

追加zPosition可以叫图层盖在另图层上面,这个价还与3D动画有关联。

10 设置阴影

连带属性:shadowOpacity,
shadowColorshadowOffsetshadowRadius

  • shadowOpacity:是一个须在0.0(不可见)和1.0(完全不透明)之间的浮点数。
  • shadowColor:控制正在阴影的颜料,和borderColorbackgroundColor同等,它的门类为是CGColorRef。阴影默认是黑色,大多数时刻你要的影也是黑色的。
  • shadowOffset:控制正在阴影的动向以及去。它是一个CGSize的值,宽度控制就阴影横向的倒,高度控制在纵向的倒。shadowOffset的默认值是{0, -3},意即阴影相对于Y轴有3只点之腾飞移动(也就是说阴影在地方)。
  • shadowRadius:控制着阴影的混淆度,当其的值是0的时节,阴影就跟视图一样发生一个那个确定的边界线。当值越来越深之早晚,边界线看上去就是会见更为混淆和本。苹果自家的动设计更偏于为自然的影子,所以一个非零值再适合不过了。

当阴影形状都知道之时段,可以通过安装shadowPath属性来一直设置阴影的模样,因为影子的计量尤其是当寄宿图所在layer透明的当儿会耗费资源。

11 设置蒙版

CALayer有只mask属性,是一个CALayer类型,不同为那些绘制在父图层中之子图层,mask图层定义了父图层的局部可见区域,这个图层的实际上内容不重要,重要的凡他的概貌,如果他于父图层小,则会拿父图层切割成自己的轮廓形状。

图片 5

mask图层.png

12 拉伸了滤算法

layer的minificationFiltermagnificationFilter个别代表图层的缩小与加大的拉伸了滤算法,均产生三栽价值:

  • kCAFilterLinear:线性过滤
  • kCAFilterNearest:最近过滤
  • kCAFilterTriline:三线性过滤
    里头线性过滤与三线性过滤效果几乎差不多,都是收获附近的几独如从平均来算新像素,能够赢得比较平缓的图像。最近过滤则顾名思义是抱最好相仿他的像素来计量新像素,在图像斜线少、差异特别强烈的时节会拿走好好之成效,否则会充满马赛克。

图像变换

1 仿射变换

UIView的transform属性是一个CGAffineTransform类型,用于在二维空间做旋转,缩放和平移。CGAffineTransform是一个可同二维空间向量(例如CGPoint)做乘法的3X2之矩阵。

图片 6

仿射变换矩阵.jpeg

CGAffineTransform备受之“仿射”的意是随便变换矩阵用什么价值,图层中平行的一定量久线在转移之后任然保持平行。
如若您对矩阵完全不熟悉,可以利用以下函数创建CAAffineTransform对象:

  • CGAffineTransformMakeRotation(CGFloat angle)
  • CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
  • CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)

UIView可以透过安装transform性能做变换,但实际她仅仅是包装了里图层的转移。
CALayer同样也起一个transform性,但它们的类别是CATransform3D,而不是CGAffineTransform。CALayer对应于UIView的transform特性叫做affineTransform
采用图层的affineTransform性能对图片做顺时针45渡过旋转:

CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
self.layerView.layer.affineTransform = transform;

CGAffineTransformMakeRotation函数接受一个弧度作为参数,而无是角度值。

一旦既而指向图像做旋转,又要针对图像做活动怎么处置?Core
Graphics提供了同样密密麻麻的函数可以以一个更换的底子及举行重新充分层次之转移:

  • CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
  • CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
  • CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat
    ty)
    这种转移称为混合变换,其中参数t就是首先步而召开的换。
    当需要一个什么还非开的开始变换的时刻,可以采用常量:CGAffineTransformIdentity
    如需要混合两独已经是的变矩阵,就好以如下方法,在少只转移的根基及缔造一个初的转换:
    CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

变的各个会潜移默化最后之结果,如果你针对一个图像先缩小到50%,再盘30过,最后走200诸如从,则最终之动结果会是倾斜向移动100如从。

2 3D变换

CGAffineTransform类似,CATransform3D为是一个矩阵,但是和2×3之矩阵不同,CATransform3D是一个得以3维空间内举行变换的4×4底矩阵:

图片 7

三维变换.jpeg

CGAffineTransform矩阵类似,Core
Animation提供了平系列之点子用来创造与烧结CATransform3D种类的矩阵,和Core
Graphics的函数类似,但是3D的倒和转多地处了一个z参数,并且旋转函数除了angle外多发生了x,y,z老三单参数,分别控制了每个坐标轴方向及的团团转:

  • CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y,
    CGFloat z)
  • CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)
  • CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)
    z轴垂直于屏幕,往眼睛方向也正方向,绕z轴旋转其实就算是2D仿射变换里面的盘。
    本着图层沿y轴转动45度:

CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
self.layerView.layer.transform = transform;

图片 8

y.jpeg

关押起图层并无叫盘,而是只有在档次方向直达之一个调减,是哪里有了问题呢?
事实上全没有错,视图看起又小实际上是为我们当就此一个斜向的观看它,而未是透视

3 透视投影

每当实际世界被,当物体远离我们的上,由于视角的原由看起会变换多少,理论及说离家我们的视图的限设较接近视角的边跟短,但实际上并没起,而我辈目前底见地是相当去的,也就是是以3D转移着任然保持平行,和事先提到的仿射变换类似。
当等距投影中,远处的体与就地的物体保持一如既往的缩放比例,这种投影也闹它好之用途(例如盘绘图,颠倒,和伪3D视频),但时咱们并不需要。
为了开片修正,我们需要引入投影变换(又如作z变换)来针对除了旋转之外的更换矩阵做有修改,Core
Animation并从未于咱提供设置透视变换的函数,因此我们得手动修改矩阵值,幸运的是,很粗略:
CATransform3D的透视效果通过一个矩阵中一个不行简单的要素来决定:m34m34用以按比例缩放X和Y的价来计量到底要离视角多远。

图片 9

m34.jpeg

m34的默认值是0,我们可由此安装m34否-1.0 /
d来采取透视效果,d代表了想象着见相机和屏幕里的去,以像素为单位,通常500-1000即使曾杀好了。

4 灭点

当于透视角度绘图的下,远离相机视角的体将会晤转换多少变多,当远离到一个巅峰距离,它们或就是缩成了一个接触,于是有的物体最后都围拢消失于与一个沾。
于切实中,这个点一般是视图的着力,于是为当以中创造拟真效果的透视,这个点当聚在屏幕中央,或者至少是富含有3D对象的视图中点。Core
Animation定义了此点在变换图层的anchorPoint(通常位于图层中心,但也发两样)。这就是说,当图层发生转移时,这个点永远在图层变换之前anchorPoint的职位。

5 sublayerTransform属性

如若来差不多独视图或者图层,每个都做3D转移,那就算需各自安装同一之m34值,并且保证于变之前都以屏幕中央一块享同一个position,比较麻烦。
CALayer有一个性质叫做sublayerTransform。它呢是CATransform3D类型,但跟指向一个图层的易不同,它影响到持有的子图层。这意味你得一次性对含蓄这些图层的器皿做变换,于是有的子图层都活动连续了之变换方式。

CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500.0;// 保证子图层拥有相同的透视投影
self.containerView.layer.sublayerTransform = perspective;
CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
self.layerView1.layer.transform = transform1;
CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
self.layerView2.layer.transform = transform2;
admin

网站地图xml地图