iOS核心动画CoreAnimation系统进阶(赛贝尔曲线-菜单侧滑动画拆分动画详解)

2023-11-02

我们知道动画是基于绘制的,多次绘制贝塞尔的过程就会形成动画。流畅的动画效果会给用户带来不一样的使用体验,下面我们就让App开发中经常使用到的侧滑动画进行拆分详解。

效果图如下:

这里写图片描述

为侧滑动画封装一个slideMenuView
绘制侧滑动画需要下面几个步骤

  • 1.添加模糊背景
#define menuBlankWidth 50
#define menuBtnHeight 40
#define buttonSpace 30

#import "slideMenuView.h"
#import "slideMenuBtn.h"

@implementation slideMenuView{
    UIVisualEffectView *blurView;
    UIView *helperSideView;
    UIView *helperCenterView;
    UIWindow *keyWindow;
    BOOL swiched;
    CGFloat diff;
    UIColor *menuColor;
    CADisplayLink *displayLink;
    NSInteger animationCount;
}

#pragma mark - lifeCycle
-(id)initWithBtnTitle:(NSArray *)btnTitles{

    self =[super init];
    if (self) {
        menuColor =[UIColor colorWithRed:0 green:0.722 blue:1 alpha:1];
        //将模糊背景添加到keyWindow上面,不会被遮挡
        keyWindow =[UIApplication sharedApplication].keyWindow;
        //灰色模糊背景
        blurView =[[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
        blurView.frame = keyWindow.frame;
        blurView.alpha = 0.5;

        [keyWindow addSubview:self];

    }
    return self;
}
  • 2.滑入菜单栏
 #define menuBlankWidth 50
#define menuBtnHeight 40
#define buttonSpace 30

#import "slideMenuView.h"
#import "slideMenuBtn.h"

@implementation slideMenuView{
    UIVisualEffectView *blurView;
    UIView *helperSideView;
    UIView *helperCenterView;
    UIWindow *keyWindow;
    BOOL swiched;
    CGFloat diff;
    UIColor *menuColor;
    CADisplayLink *displayLink;
    NSInteger animationCount;
}

#pragma mark - lifeCycle
-(id)initWithBtnTitle:(NSArray *)btnTitles{

    self =[super init];
    if (self) {
        menuColor =[UIColor colorWithRed:0 green:0.722 blue:1 alpha:1];
        //将模糊背景添加到keyWindow上面,不会被遮挡
        keyWindow =[UIApplication sharedApplication].keyWindow;
        //灰色模糊背景
        blurView =[[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
        blurView.frame = keyWindow.frame;
        blurView.alpha = 0.5;

        //这是贝塞尔曲线绘制的蓝色矩形下面的背景View
        self.frame = CGRectMake(-(CGRectGetWidth(keyWindow.frame)/2+menuBlankWidth), 0, CGRectGetWidth(keyWindow.frame)/2+menuBlankWidth, CGRectGetHeight(keyWindow.frame));
        self.backgroundColor =[UIColor clearColor];

        [keyWindow addSubview:self];

    }
    return self;
}

上面代码中的 self.frame设置的是下面图片中红色的背景View,它比蓝色弹出View多出menuBlankWidth的长度

这里写图片描述

//绘制蓝色图层 贝塞尔曲线
-(void)drawRect:(CGRect)rect{
    UIBezierPath *path =[UIBezierPath bezierPath];
    //初始点 01点
    [path moveToPoint:CGPointMake(0, 0)];
    //绘制最上面的那条直线 02线
    [path addLineToPoint:CGPointMake(CGRectGetWidth(keyWindow.frame)/2, 0)];
    /*
     一阶曲线
     addQuadCurveToPoint终点位置,位于中间 03点
     controlPoint  控制点 位于中间 03点
     */
    [path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(keyWindow.frame)/2, CGRectGetHeight(keyWindow.frame)) controlPoint:CGPointMake(CGRectGetWidth(keyWindow.frame)/2,  CGRectGetHeight(keyWindow.frame)/2)];
    //绘制最下面的那条直线 04线
    [path addLineToPoint:CGPointMake(0, CGRectGetHeight(keyWindow.frame))];
    //05线 没必要画,可以使用贝塞尔闭合
    [path closePath];//矩形绘画完毕

    //获取上下文,相当于一个画板
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextAddPath(context, path.CGPath);

    //填充颜色-蓝色
    [menuColor set];
    CGContextFillPath(context);

    //矩形绘制好后,如何让它动起来?
}

下图是上面代码根据贝塞尔曲线绘制的几个点线位置图
这里写图片描述

  • 3.思考:那么我们如何让蓝色的View右边框有类似于弹簧动画的效果呢?
    通过2个辅助view helperSideView helperCenterView,求出它们的差值,获取到一组动态的数据

我们需要借助两个小的view在固定区域内做弹簧动画
这里写图片描述

#pragma mark - lifeCycle
-(id)initWithBtnTitle:(NSArray *)btnTitles{

    self =[super init];
    if (self) {

        代码略...
        helperSideView =[[UIView alloc]initWithFrame:CGRectMake(-40, 0, 40, 40)];
        helperSideView.backgroundColor =[UIColor greenColor];
        helperCenterView = [[UIView alloc]initWithFrame:CGRectMake(-40, CGRectGetHeight(keyWindow.bounds)/2 -20, 40, 40)];
        helperCenterView.backgroundColor =[UIColor orangeColor];
        [keyWindow addSubview:helperSideView];
        [keyWindow addSubview:helperCenterView];
        [keyWindow insertSubview:self belowSubview:helperSideView];

    }
    return self;
}
#pragma mark -Action
//点击按钮
-(void)switchAcition{
    if (!swiched) {
        //1.添加模糊背景
        [keyWindow insertSubview:blurView belowSubview:self];
        //2.滑入菜单栏
        //UIView的滑入动画
        [UIView animateWithDuration:.3 animations:^{
            //切换frame
            self.frame = self.bounds;
        }];
        //3.添加弹簧动画
        /*
         Duration:持续时间
         delay:延时
         usingSpringWithDamping:弹簧阻力
         initialSpringVelocity:弹簧的初始化速度
         options:UIViewAnimationOptionBeginFromCurrentState:选项 动画选项从当前状态开始
         completion:完成以后的操作
         */
        [UIView animateWithDuration:.7 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:.9 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            //让helperSideView滑至整屏的中心点位置
            self->helperSideView.center = CGPointMake(self->keyWindow.center.x, CGRectGetHeight(self->helperSideView.bounds)/2);
        } completion:nil];

        [UIView animateWithDuration:.7 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:.9 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            //让helperSideView滑至整屏的中心点位置
            self->helperCenterView.center =self->keyWindow.center;
        } completion:nil];
        swiched = YES;
    }else{
        [self dismissView];
    }
}

//消失
-(void)dismissView{
    swiched = NO;
}
  • 添加模糊背景层手势,使view恢复,然后我们看下效果
#pragma mark - lifeCycle
-(id)initWithBtnTitle:(NSArray *)btnTitles{

    self =[super init];
    if (self) {
        省略代码...
        //添加手势
        UITapGestureRecognizer * tap =[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(dismissView)];
        [blurView addGestureRecognizer:tap];
    }
    return self;
}
//消失
-(void)dismissView{
    swiched = NO;
    //消失时同样有一个动画
    [UIView animateWithDuration:.3 animations:^{
        //回到初始位置
        self.frame = CGRectMake(-(CGRectGetWidth(self->keyWindow.frame)/2+menuBlankWidth), 0, CGRectGetWidth(self->keyWindow.frame)/2+menuBlankWidth, CGRectGetHeight(self->keyWindow.frame));
        self->blurView.alpha = 0;
        self->helperSideView.center = CGPointMake(-20, 20);
        self->helperCenterView.center = CGPointMake(-20, CGRectGetHeight(self->keyWindow.bounds)/2);
    }];
}

这里写图片描述

  • CADisplayLink 求差值

修改两个小的view的阻力和初始化速度,那么它们两个之间会产生x差值

[UIView animateWithDuration:.7 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:.9 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            //让helperSideView滑至整屏的中心点位置
            self->helperSideView.center = CGPointMake(self->keyWindow.center.x, CGRectGetHeight(self->helperSideView.bounds)/2);
        } completion:nil];

        [UIView animateWithDuration:.7 delay:0 usingSpringWithDamping:.8 initialSpringVelocity:2 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            //让helperSideView滑至整屏的中心点位置
            self->helperCenterView.center =self->keyWindow.center;
        } completion:nil];

使用CADisplayLink类 类似于定时器,60次/进行绘制s

#pragma mark - func
//添加定时器
//CADisplayLink定时器获取差值
-(void)getDiff{
    if (!displayLink) {
        displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAuction:)];
        //将displayLink添加到runLoop
        [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    }
}
-(void)displayLinkAuction:(CADisplayLink *)link{
    //presentationLayer 实时layer数据
    CALayer * layer1 = helperSideView.layer.presentationLayer;
    CALayer * layer2 = helperCenterView.layer.presentationLayer;

    //获取layer的frame
    CGRect r1 = [[layer1 valueForKeyPath:@"frame"] CGRectValue];
    CGRect r2 = [[layer2 valueForKeyPath:@"frame"] CGRectValue];

    //获取二者之间的差值
    diff = r1.origin.x - r2.origin.x;
}

#pragma mark -Action
//点击按钮
-(void)switchAcition{
    if (!swiched) {
        省略代码...
        //获取差值
        [self getDiff];

        swiched = YES;
    }else{
        [self dismissView];
    }
}
  • 使用差值,利用赛贝尔曲线进行绘制
-(void)displayLinkAuction:(CADisplayLink *)link{
    省略代码...
    //获取二者之间的差值
    diff = r1.origin.x - r2.origin.x;

    //重绘
    [self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect{
   省略代码...
    [path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(keyWindow.frame)/2, CGRectGetHeight(keyWindow.frame)) controlPoint:CGPointMake(CGRectGetWidth(keyWindow.frame)/2 + diff,  CGRectGetHeight(keyWindow.frame)/2)];
   省略代码...
}

这里写图片描述

记得在动画完成时,移除定时器

#pragma mark - func
//移除定时器
-(void)removeDisplayLink{
    [displayLink invalidate];
    displayLink = nil;
}
[UIView animateWithDuration:.7 delay:0 usingSpringWithDamping:.8 initialSpringVelocity:2 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            //让helperSideView滑至整屏的中心点位置
            self->helperCenterView.center =self->keyWindow.center;
        } completion:^(BOOL finished){
            [self removeDisplayLink];
        }];
  • 添加按钮,并给按钮添加动画
#pragma mark - lifeCycle
-(id)initWithBtnTitle:(NSArray *)btnTitles{

    self =[super init];
    if (self) {
         省略代码... 
        //添加按钮
        [self addBtnTitles:btnTitles];
    }
    return self;
}
#pragma mark - func
-(void)addBtnAnim{
    for (int i=0; i< self.subviews.count; i++) {
        UIView *btn = self.subviews[i];
        btn.transform = CGAffineTransformMakeTranslation(-100, 0);
        [UIView animateWithDuration:.7 delay:i *(0.3/self.subviews.count) usingSpringWithDamping:.6 initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
            btn.transform = CGAffineTransformIdentity;
        } completion:nil];
    }
}

//添加按钮
-(void)addBtnTitles:(NSArray *)titles{
    CGFloat space = (CGRectGetHeight(keyWindow.bounds)-titles.count * menuBtnHeight - (titles.count-1)*buttonSpace)/2;
    for (int i=0; i < titles.count; i++) {
        slideMenuBtn  *btn =[[slideMenuBtn alloc]initWithTitle:titles[i]];
        btn.center = CGPointMake(CGRectGetWidth(keyWindow.bounds)/4, space + menuBtnHeight*i + buttonSpace*i);
        btn.bounds = CGRectMake(0, 0, CGRectGetWidth(keyWindow.bounds)/2 - 20* 2, menuBtnHeight);
        btn.btnClickBlock=^(){
            NSLog(@"%@",titles[i]);
        };
        [self addSubview:btn];
    }
}
#pragma mark -Action
//点击按钮
-(void)switchAcition{
    if (!swiched) {
    省略代码...
        //获取差值
        [self getDiff];
        //添加按钮的动画
        [self addBtnAnim];
        swiched = YES;
    }else{
        [self dismissView];
    }
}

gitHub完整代码参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS核心动画CoreAnimation系统进阶(赛贝尔曲线-菜单侧滑动画拆分动画详解) 的相关文章

  • iOS进阶_密码学(四.抽取登录网络请求的单例)

    登录业务逻辑完善 在网络开发中 一般会有一个单例负责所有的网络请求 将这个网络登录的部分代码抽取出来 新建一个 类 复制方法 调整参数 测试登录能否成功运行 WTNetworkTools h import
  • iOS进阶_GCD(二.GCD串行队列&并发队列)

    GCD 核心概念 将任务添加到队列 指定任务执行的方法 任务 使用block封装 block 就是一个提前准备好的代码块 在需要的时候执行 队列 负责调度任务 串行队列 一个接一个的调度任务 并发队列 可以同时调度多个任务 任务执行函数 任
  • iOS进阶—Runtime基础

    iOS进阶 目录 GitHub参考 RunTime 基础 一个程序的执行过程 大概就是代码 gt 编译链接 gt 执行 C语言 import
  • iOS进阶_WebDav(五.WebDav的上传进度&多线程下载思路)

    WebDav的上传进度 import ViewController h interface ViewController
  • iOS架构-组件化(项目实战-项目首页架构)

    UI架构设计 设计模式 外观模式 代理模式 适配器模式 adapter 注意 一版本只是搭建结构 一 1 0 Tab搭建 二 1 1 新增UICollectionView 主页 gt 整体设计基于 gt UICollectionView 滑
  • iOS架构师_架构模式(代理,block,通知,MVC,MVP,MVVM)

    1 什么是架构 没有明确的定义 属于设计的一方面 没明确的把设计和架构进行区分 它可以小到类与类之间的交互 大到不同模块之间 以及不同业务之间的交互 都可以从架构的层面去理解它 所有架构和设计模式的目的都是为了解耦合 2 基本的架构基础 案
  • iOS进阶—Runtime源码解析:动态方法解析

    GitHub参考 PS 参考GitHub分享的objc runtime master代码 及Runtime003代码 iOS进阶 目录 接上文iOS进阶 Runtime源码解析 消息发送 查看Runtime源码 No implementat
  • iOS核心动画CoreAnimation系统进阶(赛贝尔曲线-菜单侧滑动画拆分动画详解)

    我们知道动画是基于绘制的 多次绘制贝塞尔的过程就会形成动画 流畅的动画效果会给用户带来不一样的使用体验 下面我们就让App开发中经常使用到的侧滑动画进行拆分详解 效果图如下 为侧滑动画封装一个slideMenuView 绘制侧滑动画需要下面
  • iOS进阶_多线程(二.线程间的状态)

    ViewController m 004 NSThread状态 Created by mac on 2018 4 27 Copyright 2018年 mac All rights reserved import ViewControlle
  • iOS架构师_SDWebImage源码分析

    1 对SDdemo的分析 针对SD的3 8 2版本进行分析 因为从git上面直接下载SD的源码 项目运行会报错 缺少libwebp这个库 我们下载3 8 2版本 运行 libwebp 是个webp的图片格式 属于谷歌的库 所以只能翻墙去国外
  • iOS自动化布局-AutoLayout约束优先级

    约束的优先级 AutoLayout添加的约束中也有优先级 Priority 优先级的数值1 1000 分为两种情况 一种情况是我们经常添加的各种约束 默认值1000 最大值 优先执行 条件允许的话系统会自动满足我们的约束需求 第二种就是固有
  • Objective-C实现链式编程语法(DSL)

    您越着急开始写代码 代码就会花费越长的时间 Carlson University of Wisconsin 前言 熟悉Objective C这一门编程语言的人都知道 Objective C中方法的调用都是通过中括号 实现的 比如 self
  • iOS进阶_密码学(二.钥匙串访问)

    网络开发中的原则 在网络上不允许传输用户的明文隐私数据 在本地不允许保存用户的明文隐私数据 类似于QQ 微信的记住密码 在客户端本地保存用户加密后的密码 NSUserDefaults 明文保存才能反算 能够反算的算法 钥匙串访问 开放给开发
  • iOS进阶_NSURLConnection(被弃用的原因:Connection的缺点)

    NSURLConnection下载 我们在前面的文章中介绍了MAC电脑搭建Apache服务器 在Sites文件夹中放置一个视频文件MVVM mp4 pbb 通过NSURLConnection进行下载 访问http localhost 我们可
  • iOS架构师_消息转发机制

    1 动态方法解析 对象在收到无法处理的消息时 会调用下面的方法 前者是调用类方法时会调用 后者是调用对象方法时会调用 未实现类方法调用 BOOL resolveClassMethod SEL sel 未实现实例方法调用 BOOL resol
  • iOS开发之ReactiveCocoa框架(RAC)第五篇队列与高级函数

    h文件 import ViewController h import ReactiveCocoa interface ViewController end implementation ViewController void viewDid
  • iOS开发之Runtime运行时机制

    摘要 Objective C是基于C加入了面向对象特性和消息转发机制的动态语言 除编译器之外 还需用Runtime系统来动态创建类和对象 进行消息发送和转发 作者通过分析Apple开源的Runtime代码来深入理解OC的Runtime机制
  • iOS进阶_密码学进阶(三.非对称加密算法-RSA公钥私钥的生成)

    应用场景 集成支付宝SDK 会看见 p12文件也有 非对称加密算法 一 运行终端 生成私钥 1 cd Users mac Desktop iOS 加密 2 openssl genrsa out private pem 512 生成私钥 注意
  • iOS进阶_NSURLSession(二.断点续传)

    断点续传 从上一篇文章中 我们了解了使用NSURLSession进行文件下载 我们在其基础上继续探索NSURLSession的断点续传 在NSURLSession中 我们使用reumeData来存储下载的数据进度 import ViewCo
  • iOS进阶_kvc使用注意事项

    细节1 我们在项目中使用kvc 在设置model属性的时候 注意尽量不要使用基本数据类型 实例 数据模拟 注意age是null类型的 Person h import

随机推荐

  • unity UGUI之Button按钮多种触发方式实现(有参无参函数)

    UGUI之Button按钮有多种触发方式 下面讲两种 第一种方法是在依靠属性面板绑定物体然后找到物体脚本上的方法触发 第二种是用纯代码的方式是用onClick方法 第一种 首先建立一个button 之后看button属性 如图右下角 那里的
  • 【DL】第 4 章:目标检测和图像分割

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 【HBZ分享】Redis的缓存雪崩+穿透+击穿如何解决

    缓存雪崩 现象 大量热点key设置了相同过期时间 导致同时过期 或 Redis宕机 使请求瞬间大量打到DB上 解决方案 1 搭建高可用集群环境 防止某台Redis服务宕机 2 存数据的过期时间设置随机数 防止同一时间大量数据过期 3 设置k
  • cmd命令查询硬盘序列号,磁盘ID,MAC地址

    查询单位计算机基础信息 需要查询 硬盘序列号 磁盘ID MAC地址等计算机相关信息 不需要专业的软件如AIDA 用cmd命令行就可以实现这些信息的查询 之前就经常把硬盘序列号和磁盘ID搞混乱 win r 输入cmd 打开cmd命令 1 硬盘
  • ABAP 访问REST服务设置Auth2的Token

    DATA json ser TYPE REF TO cl trex json serializer json des TYPE REF TO cl trex json deserializer DATA lv url TYPE string
  • Latex 希腊字母大写

    大写 小写 LaTeX 大写 大写 LaTeX A A quad alpha A A alpha N
  • 程序访问的局部性原理

    程序访问的局部性原理 程序访问的局部性原理包括时间局部性和空间局部性 时间局部性是指在最近的未来要用到的信息 很可能是现在正在使用的信息 因为程序中存在循环 空间局部性是指在最近的未来要用到的信息 很可能与现在正在使用的信息在存储空间上是连
  • OD华为机试 32

    组成最大数 描述 小组中每位都有一张卡片 卡片上是6位内的正整数 将卡片连起来可以组成多种数字 计算组成的最大数字 输入描述 号分割的多个正整数字符串 不需要考虑非数字异常情况 小组最多25个人 输出描述 最大的数字字符串 示例一 输入 2
  • elk 笔记15--mapping

    elk 笔记15 mapping 1 mapping 简介 1 1 什么是mapping 1 2 为何移除多type 2 mapping 数据类型 3 mapping 元字段 4 mapping 参数 5 动态 mapping 6 常见 m
  • 3.Unity Shader 基础

    目录 一对好兄弟 材质和Unity Shader Unity中shader ShaerLab Unity Shader 的结构 1 创建 2 Properties 3 SubShader 状态设置 RenderSetup SubShader
  • hive永久注册udf函数小例子

    来源 我是码农 转载请保留出处和链接 本文链接 http www 54manong com id 1217 注册UDF函数 1 helloUDF java中package信息需要修改 代码如下 package com maven udf p
  • ChatGLM2_6b安装

    Chatglm2 6b安装 一 安装要求 1 硬件 能否使用 或者以什么模式使用主要取决于显卡的显存 2 能否使用AMD显卡 可以 甚至可以使用CPU 但是需要降低精度 以CPU模式运行大概需要32GB 内存 二 工程与下载 官方路径 工程
  • 遇到问题之-yum update无法连接镜像问题解决

    yumupdate出现无法解析的错误 查看yum源设置也正确 然后查看本机DNS无法解析 通过防火墙开放DNS端口解决 然后还是无法yum安装 查看另外一台服务器和故障机配置都相同 但是yum正常 发现两者不同的是load的mirror是不
  • 物联网mqtt消息格式定义示例

    物联网mqtt消息格式定义示例 物联网mqtt通信流程 消息定义 应用下发到云 POST https 云服务器ip iot product id device id cmd Content Type application json X A
  • Spring MVC应用的开发步骤

    Spring MVC应用的开发步骤 Spring MVC应用的开发步骤 如果以异步方式提交请求 利用XML配置文件 配置控制器类 Spring MVC应用的开发步骤 下面简单介绍Spring MVC应用的开发步骤 在web xml文件中配置
  • Frida hook Java层

    往期推荐 frida环境安装 Xposed框架安装 使用及插件开发 HOOK startActivity HOOK框架 动态代理 需要相关资料的朋友 可以 加入此处即可打包获取 需要对在进程外传递的消息进行拦截处理就必须采取一种称为HOOK
  • Hexo博客开发之——七牛云图片批量下载

    一 前言 基于hexo Github搭建的静态博客 图片等资源的存储是一个问题 之前考虑过图片保存本地文件夹 图床 qiniu 微博 等 但是七牛存储的图片会有一些问题 使得我不得不考虑领寻图片等资源的存储问题 1 1 七牛图片存储的问题
  • UE4 加载流关卡(StreamingLevel)

    主要内容 本文主要讲解流关卡的加载卸载以及使用流关卡的好处 使用流关卡的好处在于利于多人协同合作 例如使用SVN进行项目开发时 各自上传或修改各自负责的关卡可以互不干扰 实现步骤 1 新建一个默认的主关卡和两个空的关卡 2 在主关卡里把两个
  • 解决 Ubuntu18.10 无法安装 Nvidia-docker2

    2023年5月18日更新 nvidia 原 github io 网页已废弃 更新了新的主页链接 2022年8月10日更新 很高兴看到这篇文章能够帮助一些同仁 在此更新一下 根据 https nvidia github io nvidia d
  • iOS核心动画CoreAnimation系统进阶(赛贝尔曲线-菜单侧滑动画拆分动画详解)

    我们知道动画是基于绘制的 多次绘制贝塞尔的过程就会形成动画 流畅的动画效果会给用户带来不一样的使用体验 下面我们就让App开发中经常使用到的侧滑动画进行拆分详解 效果图如下 为侧滑动画封装一个slideMenuView 绘制侧滑动画需要下面