iOS实现贝塞尔曲线动画

本文实例为大家分享了iOS实现贝塞尔曲线动画的具体代码,供大家参考,具体内容如下

效果如图:

仿美人相机,手势滑动隐藏顶部view。为了方便讲解,将屏幕分为几个区域,如图:

在拖动过程中:

1、拖动距离小于minMoveDistance,贝赛尔曲线发生形变
2、拖动大于minMoveDistance,整个view开始下移

在松开手时:

1、拖动距离小于minMoveDistance,未发生位移,贝塞尔曲线恢复形变
2、拖动大于minMoveDistance,小于minDisappearDistance,贝塞尔曲线恢复形变、位移回到初始位置。
3、拖动大于minDisappearDistance,向下移动隐藏view

一、根据y轴位移量确定贝塞尔路径

在拖动时曲线形变、松手时曲线恢复形变的时候都需要改变贝塞尔曲线,实际上是改变二阶贝塞尔曲线的控制点,因此写一个方法,根据传入的y轴位移量得到新的贝塞尔路径:

- (CGPathRef)getPathWithMoveDistance:(CGFloat)distance{

    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint startPoint = CGPointMake(0, 0);
    CGPoint controlPoint = CGPointMake(self.bounds.size.width*0.5, 60+distance);
    CGPoint endPoint = CGPointMake(self.bounds.size.width, 0);

    [path moveToPoint:startPoint];
    [path addQuadCurveToPoint:endPoint controlPoint:controlPoint];

    [path addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height)];
    [path addLineToPoint:CGPointMake(0, self.bounds.size.height)];

    return path.CGPath;
}

二、初始化图形

初始化的时候,可以根据上一步的方法,传入位移量0,获取贝塞尔路径,并将获得的路径赋给CAShapeLayer:

- (id)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        self.originY = frame.origin.y;
        [self setUpLayer];
        [self addGesure];
    }
    return self;
}

- (void)setUpLayer{
    self.topLineLayer = [CAShapeLayer layer];
    self.topLineLayer.fillColor = ColorForTheme.CGColor;
    self.topLineLayer.strokeColor = ColorForTheme.CGColor;
    self.topLineLayer.path = [self getPathWithMoveDistance:0];
    [self.layer addSublayer:self.topLineLayer];
}

三、添加手势

添加UIPanGestureRecognizer拖动手势,并处理手势拖动和结束拖动的事件。

拖动时:

1、拖动距离小于minMoveDistance,只有贝赛尔曲线发生形变,调用步奏一中的方法。
2、拖动距离大于minMoveDistance,整个view开始下移

结束拖动时:

调用revertFormY:方法,传入当前在y轴上已经发生的位移量

- (void)addGesure{
    if (self.gesture == nil) {
        self.gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    }
    [self addGestureRecognizer:self.gesture];
}

- (void)handlePan:(UIPanGestureRecognizer *)gesture{
    CGFloat distanceX = [gesture translationInView:self].x;
    CGFloat distanceY = [gesture translationInView:self].y;

    if (ABS(distanceX) > ABS(distanceY)) {
        return;
    }
    //拖动过程
    if (gesture.state == UIGestureRecognizerStateChanged) {
        NSLog(@"%f",distanceY);

        //移动少于minMoveDistance,贝赛尔曲线形变
        if (distanceY > 0 && distanceY <= minMoveDistance) {
            self.topLineLayer.path = [self getPathWithMoveDistance:distanceY];
        }
        //移动大于minMoveDistance,整个view下移
        else if (distanceY > minMoveDistance) {
            self.frame = CGRectMake(0, self.originY+distanceY-minMoveDistance, self.bounds.size.width, self.bounds.size.height);
        }
    }
    //手势结束
    if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateCancelled || gesture.state == UIGestureRecognizerStateFailed) {
        [self removeGestureRecognizer:self.gesture];
        [self revertFormY:distanceY];
    }
}

四、revertFormY:恢复形变方法

根据传入的y轴上的位移量,实现不同的效果:

1、y小于minMoveDistance,未发生位移,贝塞尔曲线恢复形变
2、y大于minMoveDistance,小于minDisappearDistance,贝塞尔曲线恢复形变、位移回到初始位置。
3、y大于minDisappearDistance,向下移动隐藏view

//手势结束后恢复或隐藏
-(void)revertFormY:(CGFloat)y{

    //y < 最小的隐藏位移距离,未发生位移,贝塞尔曲线恢复动画
    if (y < minDisappearDistance) {
        CAKeyframeAnimation *vibrate = [CAKeyframeAnimation animationWithKeyPath:@"path"];
        vibrate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        vibrate.values = @[
                           (id) [self getPathWithMoveDistance:y],
                           (id) [self getPathWithMoveDistance:-(y * 0.3)],
                           (id) [self getPathWithMoveDistance:(y * 0.2)],
                           (id) [self getPathWithMoveDistance:-(y * 0.15)],
                           (id) [self getPathWithMoveDistance:(y * 0.1)],
                           (id) [self getPathWithMoveDistance:-(y * 0.07)],
                           (id) [self getPathWithMoveDistance:(y * 0.05)],
                           (id) [self getPathWithMoveDistance:0.0]
                           ];
        vibrate.duration = 0.5;
        vibrate.removedOnCompletion = NO;
        vibrate.fillMode = kCAFillModeForwards;
        vibrate.delegate = self;
        [self.topLineLayer addAnimation:vibrate forKey:nil];
    }

    //y > 最小位移距离,发生了位移
    if(y > minMoveDistance){
        [UIView animateWithDuration:0.3 animations:^{
            CGFloat endY;
            //向上恢复view
            if (y < minDisappearDistance) {
                endY = self.originY;
            }
            //向下隐藏view
            else{
                endY = SCREEN_HEIGHT;
            }
            self.frame = CGRectMake(0, endY, SCREEN_WIDTH, self.frame.size.height);
        }];
    }
}

五、双击屏幕空白,消失的view从底部上移,恢复到初始位置

这个只是为了回到初始状态,根据实际需求实现。

//恢复到初始位置
- (void)comeBack{
    if (self.frame.origin.y <= self.originY) {
        return;
    }

    [UIView animateWithDuration:0.3 animations:^{
        self.frame = CGRectMake(0, self.originY, SCREEN_WIDTH, self.frame.size.height);
    } completion:^(BOOL finished) {
        [self revertFormY:10];
    }];
}

完整代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • IOS 贝塞尔曲线(UIBezierPath)属性、方法整理

    IOS 贝塞尔曲线详解         开发IOS的朋友都知道IOS 贝塞尔曲线的重要性,由于经常会用到这样的东西,索性抽时间就把相应所有的属性,方法做一个总结. UIBezierPath主要用来绘制矢量图形,它是基于Core Graphics对CGPathRef数据类型和path绘图属性的一个封装,所以是需要图形上下文的(CGContextRef),所以一般UIBezierPath在drawRect中使用. UIBezierPath的属性介绍: 1.CGPath:将UIBezierPath类转

  • ios 贝塞尔曲线切割圆角的方法

    ios 系统框架已经给我们提供了相应的切割圆角的方法, 但是如果在一个见面有很多控件切割的话会出现卡顿和个别不切得现在 /* 创建一个Button */ UIButton * button = [UIButton buttonWithType:(UIButtonTypeSystem)]; [button setFrame:CGRectMake(100, 100, 100, 100)]; [self addSubview:button]; /* 正厂的圆角需求处理方法 */ button.laye

  • 快速上手IOS UIBezierPath(贝塞尔曲线)

    UIBezierPath主要用来绘制矢量图形,它是基于Core Graphics对CGPathRef数据类型和path绘图属性的一个封装,所以是需要图形上下文的(CGContextRef),所以一般UIBezierPath在drawRect中使用. 使用方法 UIBezierPath 是对 CGPathRef 的封装.创建矢量图形时,拆解成一或多条线段,拼接起来,每条线段的终点都是下一条线段的起点. 具体地: 1.创建一个 UIBezierPath 对象 2.用 moveToPoint: 设置初

  • iOS贝塞尔曲线画哆啦A梦的代码实例

    看到这张图,是不是觉得挺萌的,那是如何实现的呢?在iOS中有一个类叫UIBezierPath(贝塞尔曲线),这两天研究了一下UIBezierPath和CAShapeLayer,根据别人分享的教程,画了这个萌萌的哆啦A梦. UIBezierPath: UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径.此类是Core Graphics框架关于path的一个OC封装.使用此类可以定义常见的圆形.多边形等形状 .我们使用直线.弧(arc)来创建复杂的曲

  • iOS实现贝塞尔曲线动画

    本文实例为大家分享了iOS实现贝塞尔曲线动画的具体代码,供大家参考,具体内容如下 效果如图: 仿美人相机,手势滑动隐藏顶部view.为了方便讲解,将屏幕分为几个区域,如图: 在拖动过程中: 1.拖动距离小于minMoveDistance,贝赛尔曲线发生形变 2.拖动大于minMoveDistance,整个view开始下移 在松开手时: 1.拖动距离小于minMoveDistance,未发生位移,贝塞尔曲线恢复形变 2.拖动大于minMoveDistance,小于minDisappearDista

  • Android仿百度地图小度语音助手的贝塞尔曲线动画

    本文为大家分享了Android仿小度语音助手的贝塞尔曲线动画,供大家参考,具体内容如下 废话不多说,看下面的动图,和百度的还是有点点差别,我也不修改了,很简单,我实在是没有多余的时间,还要学习其他的东西. package com.example.helang.volumewave; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; impo

  • Android动效Compose贝塞尔曲线动画规格详解

    目录 正文 贝塞尔曲线 解析动画曲线 曲线源码分析 总结 正文 写Compose动画的时候使用animateXAsState的时候会注意到一个参数——animationSpec,如下: val borderRadius by animateIntAsState( targetValue = if (isRound) 100 else 0, animationSpec = tween( durationMillis = 3000, easing = LinearEasing ) ) 此处就不深入探

  • android中贝塞尔曲线的应用示例

    前言: 贝塞尔曲线又称贝兹曲线,它的主要意义在于无论是直线或曲线都能在数学上予以描述.最初由保罗·德卡斯特里奥(Paul de Casteljau)于1959年运用德卡斯特里奥演算法开发(de Casteljau Algorithm),在1962,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表.目前广泛应用于图形绘制领域来模拟光滑曲线,为计算机矢量图形学奠定了基础.在一些图形处理软件中都能见到贝塞尔曲线,比如CorelDraw中翻译成"贝赛尔工具":而在Firewo

  • Android贝塞尔曲线实现直播点赞效果

    本文实例为大家分享了Android实现直播点赞效果的具体代码,供大家参考,具体内容如下 效果展示 原理分析 点赞效果最主要的难点和原理在于贝塞尔曲线动画的生成,我们通过图片主要讲解贝塞尔曲线动画 1.需要找到贝塞尔曲线的四个点 2.通过三级贝塞尔曲线的公式计算,获取贝塞尔曲线的轨迹路径点 3.通过设置点赞图片X,Y坐标,从而形成点赞的效果 实现步骤 1.初始化变量 //1.继承RelativeLayout public class ChristmasView extends RelativeLa

  • Android把商品添加到购物车的动画效果(贝塞尔曲线)

    当我们写商城类的项目的时候,一般都会有加入购物车的功能,加入购物车的时候会有一些抛物线动画,具体代码如下: 实现效果如图: 思路: 确定动画的起终点 在起终点之间使用二次贝塞尔曲线填充起终点之间的点的轨迹 设置属性动画,ValueAnimator插值器,获取中间点的坐标 将执行动画的控件的x.y坐标设为上面得到的中间点坐标 开启属性动画 当动画结束时的操作 难点: PathMeasure的使用 - getLength() - boolean getPosTan(float distance, f

随机推荐