转自:https://www.jianshu.com/p/5bd4e42a3115

Lottie.jpg

Overview

因为应用的下个版本的很多交互是参考Airbnb来的,而Airbnb开源了一个叫做Lottie动画库,而该库可以完成很多复杂炫酷的动画。所以在此翻译了Lottie的相应文档,熟悉其API。

通过阅读代码和Demo可以看出,Lottie是及其优秀的。它通过AE做成的动画导出JSON文件,然后前端使用Lottie直接加载JSON文件生成动画,不需要前端进行复杂的绘制等操作。同时Lottie 不仅支持iOS,还支持Mac、Android、web、React Native。而且它还具有占用内存少,加载流畅等特点,是个极其不错的第三方库。

相应文档

Lottie for iOS, macOS (and Android and React Native)

目录

  • Introduction
  • Installing Lottie
  • iOS Sample App
  • macOS Sample App
  • Objective C Examples
  • Swift Examples
  • Debugging Lottie
  • iOS View Controller Transitioning
  • Changing Animations At Runtime
  • Animated Controls and Switches
  • Adding Subviews to Animation
  • Supported After Effects Features
  • Currently Unsupported After Effects Features
  • Community Contributions
  • Alternatives
  • Why is it called Lottie?
  • Contributing
  • Issues or feature requests?

Introduction

Lottie是Android和iOS的移动库,用bodymovin解析Adobe After Effects导出为json的动画并在移动设备上生成矢量动画,适用于React Native!

这是第一次,设计师可以创建和发送漂亮的动画,无需程序员辛苦地手动去创建它.
由于动画由JSON驱动,因此它们的体积非常小,但复杂程度可能很高!
可以播放动画,调整大小,循环,加快速度,减慢速度,颠倒速度,甚至交互式地清理动画。
Lottie也可以播放或循环动画的一部分,可能性是无限的!
动画甚至可以 在运行时以各种方式更改 改变颜色,位置或任何关键的可变值。
Lottie也支持原生的UIViewController Transitions!

这只是Lottie能力的一小部分

Example1

Example2

<img src="https://upload-images.jianshu.io/upload_images/1388397-3b2a4d25296cdabd.gif?imageMogr2/auto-orient/strip" />

Example3

Abcs

Installing Lottie

Github Repo

您可以下载Lottie Github Repo和其中的Lottie.xcodeproj以构建动态或静态库。

Cocoapods

Get Cocoapods
Add the pod to your podfile

pod 'lottie-ios'

run

pod install

通过CocoaPods安装到你的项目中后,将Lottie头文件导入工程中
Objective C
#import <Lottie/Lottie.h>
Swift
import Lottie

Carthage

Get Carthage

将 Lottie 添加到 Cartfile 中

github "airbnb/lottie-ios" "master"

run

carthage update

在你的应用程序的“常规”选项卡中“链接的框架和库”,需要从Carthage / Build / iOS目录中拖放“carthage update”生成的lottie-ios.framework。

iOS Sample App

克隆这个repo,并尝试示例应用程序,
repo中包含了一个macOS示例和一个iOS示例

iOS示例应用程序演示了Lottie的几项功能

Example 1

Example 2

Example 3

动画资源管理器允许您移除,播放,循环和调整动画大小。
可以使用内置的扫描功能从应用程序包或从Lottie文件中加载动画。

macOS Sample App

下载这个 repo 并尝试运行 the Sample App,
这个repo可以构建一个macOS示例和一个iOS示例

Lottie Viewer

用于macOS的Lottie Viewer允许您拖放JSON文件用于播放,移除和循环动画。 Mac程序和iOS程序的动画代码是一样的,因此您将获得精确的Mac和iOS动画。

Objective C Examples

Lottie可以从Build中的JSON文件或URL中加载动画

如何使用JSON文件加载动画,只需将生成的JSON文件添加到xcode的工程目录下。

LOTAnimationView *animation = [LOTAnimationView animationNamed:@"Lottie"];
[self.view addSubview:animation];
[animation playWithCompletion:^(BOOL animationFinished) {// Do Something
}];

如果你需要使用bundles中的JSON文件,加载动画

LOTAnimationView *animation = [LOTAnimationView animationNamed:@"Lottie" inBundle:[NSBundle YOUR_BUNDLE]];
[self.view addSubview:animation];
[animation playWithCompletion:^(BOOL animationFinished) {// Do Something
}];

或者你可以通过NSURL以编码的方式加载动画

LOTAnimationView *animation = [[LOTAnimationView alloc] initWithContentsOfURL:[NSURL URLWithString:URL]];
[self.view addSubview:animation];

Lottie支持iOSUIViewContentModes的aspectFit,aspectFill和scaleFill

你也可以设置动画的进度.

CGPoint translation = [gesture getTranslationInView:self.view];
CGFloat progress = translation.y / self.view.bounds.size.height;
animationView.animationProgress = progress;

或者你可以只播放动画的一部分:

[lottieAnimation playFromProgress:0.25 toProgress:0.5 withCompletion:^(BOOL animationFinished) {// Do Something
}];

Swift Examples

Lottie可以从Bundle中的JSON文件或URL中加载动画

如何使用JSON文件加载动画,只需将生成的JSON文件添加到xcode的工程目录中。

let animationView = LOTAnimationView(name: "LottieLogo")
self.view.addSubview(animationView)
animationView.play{ (finished) in// Do Something
}

如果你需要使用bundles中的JSON文件,加载动画

let animationView = LOTAnimationView(name: "LottieLogo" bundle:yourBundle)
self.view.addSubview(animationView)
animationView.play()

或者你可以通过NSURL以编码的方式加载动画

let animationView = LOTAnimationView(contentsOf: WebURL)
self.view.addSubview(animationView)
animationView.play()

你也可以设置动画的进度.

let translation = gesture.getTranslationInView(self.view)
let progress = translation.y / self.view.bounds.size.height;
animationView.animationProgress = progress

或者你可以只播放动画的一部分:

animationView.play(fromProgress: 0.25, toProgress: 0.5, withCompletion: nil)

iOS View Controller Transitioning

Lottie带有一个UIViewController动画控制器,用于制作自定义viewController转换!

Transition1

Transition2

只是成为过渡的delegate

- (void)_showTransitionA {ToAnimationViewController *vc = [[ToAnimationViewController alloc] init];vc.transitioningDelegate = self;[self presentViewController:vc animated:YES completion:NULL];
}

并用LOTAnimationTransitionController实现委托方法

#pragma mark -- View Controller Transitioning
  • (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@“vcTransition1” fromLayerNamed:@“outLayer” toLayerNamed:@“inLayer” applyAnimationTransform:NO];
    return animationController;
    }

  • (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@“vcTransition2” fromLayerNamed:@“outLayer” toLayerNamed:@“inLayer” applyAnimationTransform:NO];
    return animationController;
    }

通过将applyAnimationTransform设置为YES,您可以使Lottie动画从一个视图控制器移动到另一个视图控制器。 它们将定位在图层的起源处。 设置为NO时,Lottie只是在指定z层时遮蔽具有指定层的视图控制器。

Debugging

Lottie有几个要了解的调试功能。
当加载动画时,不支持的功能,其工程名将打印在控制台中。

如果您查看LOTHelpers.h这个类,您将看到两个调试标志。 ENABLE_DEBUG_LOGGINGENABLE_DEBUG_SHAPES
ENABLE_DEBUG_LOGGING增加了Lottie Logging的详细程度。 它在动画期间随时记录一个动画节点。 如果您的动画不起作用,请将其打开并播放您的动画。 控制台日志可能会给你一些关于问题什么的线索。

ENABLE_DEBUG_SHAPES为每个图层和形状的锚点画一个彩色正方形。 这对查看屏幕上是否有任何内容很有帮助。

Keypaths

LOTAnimationView提供- (void)logHierarchyKeypaths,它将递归记录动画的所有可设置关键路径。 这有助于在运行时更改动画。

Adding Views to an Animation at Runtime

您不仅可以(在运行时更改动画),还可以在运行时将自定义UI添加到LOTAnimation中。
下面的例子是一些进度用途的动态图像加载器。

A Dynamic Image Loading Spinner

Spinner

上面的例子显示了一个单独的LOTAnimationView,它使用加载微调器动画进行设置。 加载微调器会循环一部分动画,而图像则是异步下载的。 下载完成后,图像将添加到动画中,其余动画将无缝播放。 图像完美地执行动画并被调用。

Spinner_Alt

现在,动画已由设计师更改并需要更新。 所需的只是更新包中的JSON文件。 无需更改代码!

Spinner_Dark

现在,动画已由设计师更改并需要更新。 所需的只是更新包中的JSON文件。 无需更改代码!

很强大吧 嗯?

查看下面的代码以获取示例!

import UIKit
import Lottieclass ViewController: UIViewController {var animationView: LOTAnimationView = LOTAnimationView(name: "SpinnerSpin");override func viewDidLoad() {super.viewDidLoad()// Setup our animaiton viewanimationView.contentMode = .scaleAspectFillanimationView.frame = CGRect(x: 20, y: 20, width: 200, height: 200)self.view.addSubview(animationView)// Lets change some of the properties of the animation// We arent going to use the MaskLayer, so lets just hide itanimationView.setValue(0, forKeypath: "MaskLayer.Ellipse 1.Transform.Opacity", atFrame: 0)// All of the strokes and fills are white, lets make them DarkGreyanimationView.setValue(UIColor.darkGray, forKeypath: "OuterRing.Stroke.Color", atFrame: 0)animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Stroke.Color", atFrame: 0)animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Fill.Color", atFrame: 0)// Lets turn looping on, since we want it to repeat while the image is 'Downloading'animationView.loopAnimation = true// Now play from 0 to 0.5 progress and loop indefinitely.animationView.play(fromProgress: 0, toProgress: 0.5, withCompletion: nil)// Lets simulate a download that finishes in 4 seconds.let dispatchTime = DispatchTime.now() + 4.0DispatchQueue.main.asyncAfter(deadline: dispatchTime) {self.simulateImageDownloaded()}}func simulateImageDownloaded() {// Our downloaded imagelet image = UIImage(named: "avatar.jpg")let imageView = UIImageView(image: image)// We want the image to show up centered in the animation view at 150Px150P// Convert that rect to the animations coordinate space// The origin is set to -75, -75 because the origin is centered in the animation viewlet imageRect = animationView.convert(CGRect(x: -75, y: -75, width: 150, height: 150), toLayerNamed: nil)// Setup our image view with the rect and add rounded cornersimageView.frame = imageRectimageView.layer.masksToBounds = trueimageView.layer.cornerRadius = imageRect.width / 2;// Now we set the completion block on the currently running animationanimationView.completionBlock = { (result: Bool) in ()// Add the image view to the layer named "TransformLayer"self.animationView.addSubview(imageView, toLayerNamed: "TransformLayer", applyTransform: true)// Now play the last half of the animationself.animationView.play(fromProgress: 0.5, toProgress: 1, withCompletion: { (complete: Bool) in// Now the animation has finished and our image is displayed on screenprint("Image Downloaded and Displayed")})}// Turn looping off. Once the current loop finishes the animation will stop // and the completion block will be called.animationView.loopAnimation = false}}

Changing Animations At Runtime

Lottie可以做的不仅仅是美丽的动画。 Lottie允许您在运行时更改动画

Say we want to create 4 toggle switches.

Toggle

它很容易创建四个开关并播放它们:

let animationView = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView)
animationView.frame.origin.x = 40
animationView.frame.origin.y = 20
animationView.autoReverseAnimation = true
animationView.loopAnimation = true
animationView.play()

let animationView2 = LOTAnimationView(name: “toggle”);
self.view.addSubview(animationView2)
animationView2.frame.origin.x = 40
animationView2.frame.origin.y = animationView.frame.maxY + 4
animationView2.autoReverseAnimation = true
animationView2.loopAnimation = true
animationView2.play()

let animationView3 = LOTAnimationView(name: “toggle”);
self.view.addSubview(animationView3)
animationView3.frame.origin.x = 40
animationView3.frame.origin.y = animationView2.frame.maxY + 4
animationView3.autoReverseAnimation = true
animationView3.loopAnimation = true
animationView3.play()

let animationView4 = LOTAnimationView(name: “toggle”);
self.view.addSubview(animationView4)
animationView4.frame.origin.x = 40
animationView4.frame.origin.y = animationView3.frame.maxY + 4
animationView4.autoReverseAnimation = true
animationView4.loopAnimation = true
animationView4.play()

Now lets change their colors

Recolored Toggle
animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView3.setValue(UIColor.red, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView4.setValue(UIColor.orange, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
[animationView2 setValue:[UIColor greenColor] forKeypath:@"BG-On.Group 1.Fill 1.Color" atFrame:@0];

keyPath是来自After Effects的图层和属性名称的点分离路径。

LOTAnimationView提供- (void)logHierarchyKeypaths,它将递归记录动画的所有可设置关键路径。

Key Path

"BG-On.Group 1.Fill 1.Color"

Now lets change a couple of properties

Multiple Colors
animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView2.setValue(UIColor.red, forKeypath: "BG-Off.Group 1.Fill 1.Color", atFrame: 0)

Lottie允许您更改After Effects动画制作过程中的任何属性。 如果关键帧不存在,则为您创建一个线性关键帧。 如果关键帧确实存在,那么它仅替换其数据。

Animated Controls and Switches

Animated Buttons

Lottie还拥有UIControl的自定义子类,用于创建自定义动画式交互式控件。
目前Lottie有LOTAnimatedSwitch这是一种切换式开关控制。 点击开关将播放On-Off或Off-On动画,并向所有目标发送UIControlStateValueChanged广播。 它跟UISwitch使用方式相同,同时使用Lottie设置了一些动画。

您可以使用conveneince方法或直接提供动画来初始化开关。

// Convenience
LOTAnimatedSwitch *toggle1 = [LOTAnimatedSwitch switchNamed:@"Switch"];

// Manually
LOTComposition *comp = [LOTComposition animationNamed:@“Switch”];
LOTAnimatedSwitch *toggle1 = [[LOTAnimatedSwitch alloc] initWithFrame:CGRectZero];
[toggle1 setAnimationComp:comp];

您还可以为动画的开启和关闭指定动画时间轴的特定部分。
默认情况下LOTAnimatedSwitch将向前播放动画,向后播放动画以关闭。

可以说提供的动画从0.5-1进度开始动画,从0-0.5开始动画:

/// On animation is 0.5 to 1 progress.
[toggle1 setProgressRangeForOnState:0.5 toProgress:1];

/// Off animation is 0 to 0.5 progress.
[toggle1 setProgressRangeForOffState:0 toProgress:0.5];

此外,所有LOTAnimatedControls都支持更改状态更改的外观。 这需要After Effects中的一些设置。 Lottie会根据控件状态切换可见的动画图层。 这可以用于具有禁用,选定或突出显示的状态。 这些状态与After Effects中的图层名称关联,并在控件更改状态时动态显示。

可以说我们有一个正常和禁用状态的切换开关。 在效果中,我们有一个包含常规“按钮”和禁用“禁用”状态的Precomps的组合。 他们有不同的视觉风格。

Regular
Disabled

现在在代码中,我们可以将UIControlState与这些图层相关联

// Specify the layer names for different states
[statefulSwitch setLayerName:@"Button" forState:UIControlStateNormal];
[statefulSwitch setLayerName:@"Disabled" forState:UIControlStateDisabled];

// Changes visual appearance by switching animation layer to “Disabled”
statefulSwitch.enabled = NO;

// Changes visual appearance by switching animation layer to “Button”
statefulSwitch.enabled = YES;

Supported After Effects Features

Keyframe Interpolation


  • Linear Interpolation
  • Bezier Interpolation
  • Hold Interpolation
  • Rove Across Time
  • Spatial Bezier

Solids


  • Transform Anchor Point
  • Transform Position
  • Transform Scale
  • Transform Rotation
  • Transform Opacity

Masks


  • Path
  • Opacity
  • Multiple Masks (additive, subtractive and intersection)

Track Mattes


  • Alpha Matte

Parenting


  • Multiple Parenting
  • Nulls

Shape Layers


  • Anchor Point
  • Position
  • Scale
  • Rotation
  • Opacity
  • Path
  • Group Transforms (Anchor point, position, scale etc)
  • Rectangle (All properties)
  • Eclipse (All properties)(Eclipse
  • Multiple paths in one group
  • Even-Odd winding paths
  • Reverse Fill Rule

Stroke (shape layer)


  • Stroke Color
  • Stroke Opacity
  • Stroke Width
  • Line Cap
  • Dashes (Now Animated!)

Fill (shape layer)


  • Fill Color
  • Fill Opacity

Trim Paths (shape layer)


  • Trim Paths Start
  • Trim Paths End
  • Trim Paths Offset

Repeaters


  • Supports repeater transforms
  • Offset currently not supported.

Gradients


  • Support for Linear Gradients
  • Support for Radial Gradients

Polystar and Polygon


  • Supported! Theres a known bug if the roundness is greater than 100 percent.

Layer Features


  • Precomps
  • Image Layers
  • Shape Layers
  • Null Layers
  • Solid Layers
  • Parenting Layers
  • Alpha Matte Layers

Currently Unsupported After Effects Features

  • Merge Shapes
  • Alpha Inverted Masks
  • Trim Shapes Individually feature of Trim Paths
  • Expressions
  • 3d Layer support
  • Time remapping / Layer Reverse
  • Layer Blend Modes
  • Layer Effects

Community Contributions

  • Xamarin bindings
  • NativeScript bindings
  • Appcelerator Titanium bindings
  • macOS Support added by Alex Pawlowski

Alternatives

  1. 手动构建动画。 手动构建动画是跨Android和iOS设计和工程的时间承诺。 通常很难甚至不可能证明花费这么多时间来获得动画是正确的。
  2. [Facebook关键帧](https://github.com/facebookincubator/Keyframes)。 关键帧是来自Facebook的精彩新图书馆,它们为反应而构建。 但是,关键帧不支持Lottie的一些功能,如遮罩,遮罩,修剪路径,破折号图案等。
  3. Gifs。 GIF的尺寸是bodymovin JSON尺寸的两倍多,并且以固定的尺寸渲染,无法放大以匹配大屏幕和高密度屏幕。
  4. Png序列。 Png序列比gifs更糟,因为它们的文件大小通常是bodymovin json大小的30-50倍,也不能放大。

Why is it called Lottie?

Lottie(洛蒂)是以德国电影导演和剪影动画的先驱者命名的。 她最着名的电影是“阿彻梅德王子历险记”(1926年) - 这是迄今为止最古老的长篇动画电影,在沃尔特迪斯尼的长篇白雪公主和七个小矮人(1937)之前超过十年
The art of Lotte Reineger

Contributing

贡献者非常欢迎。 只需上传一份描述您所做更改的公关。

如果你想添加更多的JSON文件,请随时这样做!

Issues or feature requests?

文件github问题的任何意外中断。 如果After Effects文件无效,请将其附加到您的问题中。 在没有原始文件的情况下进行调试要困难得多。 Lottie由[Brandon Withrow]开发和维护(mailto:brandon.withrow@airbnb.com)。 请随时通过电子邮件或[Twitter](https://twitter.com/theWithra)

Roadmap (In no particular order)

  • 添加对交互式动画过渡的支持
      </div></div>

lottie介绍及使用相关(转)相关推荐

  1. GB 18030介绍及其与相关标准的比较-GB13000(附:Unicode规范)

    GB 18030介绍及其与相关标准的比较 一.标准内容简介 1.GB 2312 2.GB13000(附:Unicode规范) 3.GBK与GB18030-2000 二.GB 18030的优点 2.GB ...

  2. GB 18030介绍及其与相关标准的比较-GBK与GB18030-2000

    GB 18030介绍及其与相关标准的比较 一.标准内容简介 1.GB 2312 2.GB13000(附:Unicode规范) 3.GBK与GB18030-2000 二.GB 18030的优点 3.GB ...

  3. 少儿编程Scratch学习教程--Scratch介绍及参赛相关

    之前写了几篇关于Scratch的使用文章.忽然想起,忘记介绍下Scratch了. Scratch是一款由麻省理工学院(MIT) 设计开发的少儿编程工具.官方网址是麻省理工学院网站的一个分支.这个软件的 ...

  4. VSCode基本介绍及安装相关+插件集合

    VSCode基本介绍及安装相关 一. 简单介绍 VSCode(全称:Visual Studio Code)是一款由微软开发且跨平台的免费源代码编辑器,可选择Windows.Linux.macOS的不同 ...

  5. GB 18030介绍及其与相关标准的比较-GB 18030的优点

    GB 18030介绍及其与相关标准的比较 一.标准内容简介 1.GB 2312 2.GB13000(附:Unicode规范) 3.GBK与GB18030-2000 二.GB 18030的优点 二.GB ...

  6. Kubernetes-基本介绍/核心功能/相关术语(一)

    1 Kubernetes介绍 单词:Kubernetes这个单词起源于希腊语,意为舵手或领航员,K8S即为缩写,其中8代表了"ubernete"这8个字符. 来源:K8S前身是Go ...

  7. Vs Code中Vue代码格式插件,Vetur、ESLint 、Prettier - Code formatter的介绍使用及相关配置

    文章目录 一.插件的介绍与安装 1.Vetur插件 2.ESLint 插件 3.Prettier - Code formatter插件 二.相关文件配置 总结 前面主要先对插件进行介绍和如何安装,之后 ...

  8. 2.oracle的安装常识,Oralce服务器,oracle集群,oracle服务介绍,用户解锁相关

     1 oracle的安装常识(oracle10g和oracle11g的版本差别): A 安装目录都不要有中文和空格 B oracle10g支持winxp 不支持win7,8和vista;Oracl ...

  9. 手动配置协议和服务器POP,在outlook上添加账户并介绍邮件协议相关知识

    在outlook上添加账户 1.首先在outlook文件 --> 添加用户 image 2. 选择 电子邮件帐户 --> 下一步 image 3. 在账户页面上设置相关信息. 您的姓名:这 ...

最新文章

  1. Spring Boot 2.0 热部署指南
  2. flutter 按钮_flutter好用的轮子推荐二-点赞按钮动画
  3. POJ - 3254 - Corn Fields
  4. 主要推荐系统算法总结及Youtube深度学习推荐算法实例概括
  5. Linux日志查看head与tail配合查看区间行数的内容
  6. ImportError: No module named 'keras.utils.visualize_util'
  7. 6-23 分离链接法的删除操作函数 (20 分)
  8. 数据数据库学通MongoDB——第一天 基础入门
  9. Mysql之drop、delete、truncate的区别
  10. Hibernate ‍java.lang.ClassCastException ERROR解决方法
  11. 运营管理整改报告范文_整改报告怎么写(安全检查整改报告范文)
  12. Jenkins分布式构建和部署(master-slave)
  13. QTableView实现冻结行冻结列
  14. AngularJS笔记
  15. 实行OBP海洋塑料认证保护海洋环境
  16. 如何使用Java获取货币符号?
  17. 钉钉自动打卡上下班微信自动打卡(原理及源码)
  18. 查看linux系统的ip
  19. shell参数带有空格问题
  20. 2021.6.21-6.28 人工智能行业每周技术动态

热门文章

  1. 计算机行业求职简历中英文职位对照
  2. 南京理工大学计算机研究生预答辩,南京理工大学论文盲审_盲审被毙掉一般是因为什么_博士论文盲审通过率...
  3. 永恒之蓝ms17-0109(缓冲区溢出漏洞)
  4. 计算机基础教学效果分析,计算机应用基础的教学反思范文
  5. 概率论【合集】--猴博士爱讲课
  6. kafka报错:Bootstrap broker localhost:9092 (id: -1 rack: null) disconnected
  7. 34岁!100天!学会Java编程(Day12)——知识点串连
  8. 天津理工大学计算机科学与工程学院院长,国家杰青徐常胜任计算机科学与工程学院院长...
  9. 二分查找算法的万能公式(LeetCode35、704、1095)
  10. c语言过河小游戏代码,闲来没事撸了一个控制台小游戏