精华内容
下载资源
问答
  • SpringView 是一个提供了上下拖拽的功能组件,能够进行高度自定义,实现各种下拉\上拉动画效果,demo里实现了:仿阿里旅行、仿美团,仿QQ下拉红包,仿acfun等
  • (关于弹幕实现,大家可以参考我前面写一篇文章IOS 自定义弹幕实现在开始我实现方案之前,大家可以先参看下这篇文章iOS 基于 IM 实现仿映客礼物连击效果,写得很好,Demo中关于礼物连乘的动画效果,就是引用...

    项目介绍:

    最近做了个直播项目,需要用到弹幕和刷礼物。在网上找了许多开源代码,发现都不是很适合自己的项目需求,于是利用空余时间将两个功能都实现下,这里分享出来,供大家一起学习。(关于弹幕的实现,大家可以参考我前面写的一篇文章IOS 自定义弹幕实现

    在开始我的实现方案之前,大家可以先参看下这篇文章iOS 基于 IM 实现仿映客刷礼物连击效果,写得很好,Demo中关于礼物连乘的动画效果,就是引用其中。但这位大神所用的缓存逻辑特别复杂,所以在控制缓存的时候有些小BUG,为了弥补这个缺陷,于是我就开始了这篇文章。

    实现功能

    在效果图中,礼物1、2、3、4四个按钮分别模拟四个人发的四种礼物,点击一次,就代表发送一条礼物消息,实现逻辑功能如下:

    1. 点击礼物1按钮,会出现一个倒计时按钮,并发送一条礼物消息

    2. 再次点击倒计时按钮,会再次发送一条礼物消息,礼物数量累加

    3. 在倒计时的时间内,倒计时按钮如果没有收到点击事件,倒计时按钮会隐藏,并且当前用来展示礼物动画的cell也会隐藏

    4. 如果当前全部的cell都在展示,这时你点击了其他类型的礼物按钮,这时的礼物消息会被缓存,等到当前礼物动画执行完时,再去执行缓存的

    5. 如果在短时间内多次点击连送按钮,连乘动画也会缓存

    实现界面功能如下:

    1. 可自定义cell样式

    2. 可自定义cell的展示和隐藏动画

    3. 可监听cell的点击事件

    下面是我实现这些功能的基本逻辑与实现代码。

    基本逻辑

    开始写代码之前,将功能的基本逻辑列出,这是个很好的习惯。特别是对于那些复杂的功能,这个习惯就显得尤为重要。

    功能要求:收到消息展示动画、可连乘、可缓存

    功能要求看起好像很简单,如果真的实现可就不是那么容易了。

    具体逻辑如下:

    1. 收到一条礼物消息

    2. 检测当前是否有相同类型的礼物消息正在展示动画

    3. 有,将该消息加入到当前的动画组中

    4. 没有,检测当前是否有空闲的轨道用于展示动画

    5. 有,取出缓存中相同类型的消息,开始执行动画

    6. 没有,将当前消息加入到消息缓存中

    7. 连乘动画完成,如果3秒内没有收到新的同类消息,就执行隐藏动画

    8. 隐藏动画完成,再取缓存,开始下一个动画,直至无缓存为止

    理清楚了逻辑之后,下面就是代码实现了,真正的痛苦现在才开始!

    实现代码

    这里我会根据逻辑顺序来介绍代码的实现。在收到一条消息之后,在外面只需调用PresentView对象的insertPresentMessages:接口方法,将消息插入进来,insertPresentMessages:接口实现代码如下:

    - (void)insertPresentMessages:(NSArray> *)models

    {

    NSArray *siftArray = [self checkElementOfModels:models];

    if (!siftArray.count) return;

    for (int index = 0; index < siftArray.count; index++) {

    id obj = models[index];

    PresentViewCell *cell = [self examinePresentingCell:obj];

    if (cell) {

    [cell shakeAnimationWithNumber:1];

    }else {

    [self.dataCaches addObject:obj];//将当前消息加到缓存中

    NSArray *cells = [self examinePresentViewCells];

    if (cells.count) {

    cell = cells.firstObject;

    NSArray *objs = [self subarrayWithObj:obj];

    __weak typeof(self) ws = self;

    [cell showAnimationWithSender:[obj sender] giftName:[obj giftName] prepare:^{

    if ([ws.delegate respondsToSelector:@selector(presentView:configCell:sender:giftName:)]) {

    [ws.delegate presentView:ws configCell:cell sender:[obj sender] giftName:[obj giftName]];

    }

    } completion:^(BOOL finished) {

    int index = 0;

    while (index < objs.count) {

    index++;

    [cell shakeAnimationWithNumber:objs.count];

    }

    }];

    }

    }

    }

    }

    这基本就是整个逻辑的实现了,看到这一堆的逻辑判断,是不是感觉头都大了。没关系,接下来我会对这个代码进行一步步的解析。

    首先,调用了PresentView对象的checkElementOfModels:方法,这就是数据检测。

    数据检测

    数据检测就是对插入的模型数组进行过滤,因为我们需要通过这个模型来确定消息的类型(礼物类型是通过发送者和发送的礼物名来确定的),所以自定义的消息模型必须要遵守PresentModelAble协议,协议要求如下:

    @required

    @property (copy, nonatomic) NSString *sender;

    @property (copy, nonatomic) NSString *giftName;

    故检测数据,其实就是检测模型数组中的元素是否遵守了PresentModelAble协议,并剔除其中没有遵守协议的数据。具体实现代码如下:

    - (NSArray *)checkElementOfModels:(NSArray> *)models

    {

    NSMutableArray *siftArray = [NSMutableArray array];

    for (id obj in models) {

    if (![obj conformsToProtocol:@protocol(PresentModelAble)]) {

    DebugLog(@"%@对象没有遵守PresentModelAble协议", obj);

    }else {

    [siftArray addObject:obj];

    }

    }

    return siftArray;

    }

    选出合适的数据之后,就是遍历该数组,对每一个元素进行动画检测。

    动画检测

    动画检测就是检测当前是否有相同类型的消息正在展示动画,即流程2。这里是遍历当前所有的cell,如果cell上展示的消息类型与该消息类型一致,并且cell的动画正在执行,就返回该cell,否则返回nil。具体实现代码如下:

    - (PresentViewCell *)examinePresentingCell:(id)obj

    {

    for (PresentViewCell *cell in self.showCells) {

    if ([cell.sender isEqualToString:[obj sender]] && [cell.giftName isEqualToString:[obj giftName]]) {

    //当前正在展示动画

    if (cell.state != AnimationStateNone) return cell;

    }

    }

    return nil;

    }

    如果动画检测检测到匹配的cell,就在cell当前的动画队列上添加一个连乘动画(shakeAnimation)任务。

    ShakeAnimation

    连乘动画就是在当前礼物数量上做一个累加的动画,即流程3。连乘动画的具体实现,大家可以自行查看demo中PresentLable对象的startAnimationDuration:completion:方法。因为连乘动画执行完,三秒后没有收到新的任务就要开始cell的隐藏动画(hiddenAnimation)。所以开始连乘动画前,需要取消掉前面延时三秒执行的隐藏动画任务,然后重新开始延时,即流程7。具体实现代码如下:

    - (void)shakeAnimationWithNumber:(NSInteger)number

    {

    [NSObject cancelPreviousPerformRequestsWithTarget:self];

    __weak typeof(self) ws = self;

    [self performSelector:@selector(hiddenAnimation) withObject:nil afterDelay:3.0];

    _state               = AnimationStateShaking;

    self.shakeLable.text = [NSString stringWithFormat:@"X%ld", ++self.number];

    [self.shakeLable startAnimationDuration:Duration completion:^(BOOL finish) {

    if (number > 1) {

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

    [ws startShakeAnimationWithNumber:(number - 1) completion:block];

    });

    }else {

    _state = AnimationStateShaked;

    if (block) {

    block(YES);

    }

    }

    }];

    }

    HiddenAnimation

    隐藏动画实现代码也非常简单,这里就不介绍了。但是需要注意的地方是,隐藏动画执行完成后需要将cell恢复到初始状态,保证cell在开始下一次展示动画之前不会因为状态的错误而导致流程判断出错。

    如果动画检测没有检测到匹配的cell,就开始cell的检测

    cell检测

    cell检测就是检测当前是否有空闲的cell用于展示礼物消息动画,即流程4.这里只需要遍历所有的cell,判断cell的动画状态就可以了。具体实现代码如下:

    - (NSArray *)examinePresentViewCells

    {

    NSMutableArray *freeCells = [NSMutableArray array];

    for (PresentViewCell *cell in self.showCells) {

    if (cell.state == AnimationStateNone) {

    [freeCells addObject:cell];

    }

    }

    return freeCells;

    }

    如果没有空闲的cell用于展示动画,就将当前消息加入到缓存中,即添加到dataCaches这个数组中,即流程6。

    如果有空闲cell用于展示,就从空闲cell数组中取出一个cell,执行cell的展示动画(showAnimation),即流程5。

    ShowAnimation

    cell的展示动画,其接口如下:

    /**

    *  显示cell动画

    *

    *  @param sender     发送者

    *  @param name       礼物名

    *  @param prepare    准备动画回调

    *  @param completion 动画完成回调

    */

    - (void)showAnimationWithSender:(NSString *)sender

    giftName:(NSString *)name

    prepare:(void (^)(void))prepare

    completion:(void (^)(BOOL finished))completion;

    因为展示动画是用来展示礼物消息的动画,在展示之前需要知道展示的礼物消息的类型,所以需要传入sender和name两个参数。

    展示动画完成之后,就需要从缓存中取出与该消息相同类型的消息,然后开始连乘动画,这些操作就可以早completion中完成。那prepare回调是干嘛呢?

    其实这里还有一个问题:在开始cell的展示动画之前,我们就需要给这个cell设置需要展示的数据。可是cell是自定义的,这是根本无法拿到自定义的cell,也就无法给这个cell设置数据?

    这里我的思路是:在开始cell的展示动画之前,就是prepare回调中,给外界一个代理通知,让外面来执行这个赋值操作。代理通知接口如下:

    /**

    *  礼物动画即将展示的时调用,根据礼物消息类型为自定义的cell设置对应的模型数据用于展示

    *

    *  @param cell        用来展示动画的cell

    *  @param sender      礼物发送者

    *  @param name        礼物名

    */

    - (void)presentView:(PresentView *)presentView

    configCell:(PresentViewCell *)cell

    sender:(NSString *)sender

    giftName:(NSString *)name;

    到这里,关于收到一条消息的流程就就全部处理完了。最后一步就是对缓存逻辑进行处理了,即上面的流程8。

    缓存处理

    缓存处理就是当一个礼物消息类型的动画处理完,即cell的隐藏动画执行完成,就要从缓存中取下一个类型的礼物消息,开始下一组动画,直至无缓存为止,即流程8。这里的隐藏动画回调是通过代理实现的,具体实现代码如下:

    - (void)presentViewCell:(PresentViewCell *)cell operationQueueCompletionOfNumber:(NSInteger)number

    {

    if (self.dataCaches.count) {

    id obj = self.dataCaches.firstObject;

    NSArray *objs = [self subarrayWithObj:obj];

    __weak typeof(self) ws = self;

    [cell showAnimationWithSender:[obj sender] giftName:[obj giftName] prepare:^{

    if ([ws.delegate respondsToSelector:@selector(presentView:configCell:sender:giftName:)]) {

    [ws.delegate presentView:ws configCell:cell sender:[obj sender] giftName:[obj giftName]];

    }

    } completion:^(BOOL finished) {

    [cell shakeAnimationWithNumber:objs.count];

    }];

    //        [self insertPresentMessages:self.dataCaches completion:self.completion];

    }else {

    [cell releaseVariable];

    }

    }

    其实这里的处理就重复流程5。最后缓存处理完了就调用releaseVariable方法释放相关引用内存。

    至此,整个刷礼物效果的基础逻辑就以实现了。这里就完了吗?当然,还没有!任何一个功能实现之后,没有经过反复的测试、修改、优化等流程的检验,就都不算完成。

    后续

    由于篇幅原因,关于这个刷礼物效果功能的优化与bug的修改,我会在下一篇文章进行说明。

    最后奉上Demo(优化后)的下载地址

    展开全文
  • 在将登录页面搭好后,我想试试能不能通过WPF强大的动画功能制作出登录面板渐显渐隐效果,在上网查阅了相关资料后,我找到了一个能帮助我做出此效果一个属性:UIElement.OpacityMask属性。 先来介绍一下UIElement...

    在将登录页面搭好后,我想试试能不能通过WPF强大的动画功能制作出登录面板的渐显渐隐效果,在上网查阅了相关资料后,我找到了一个能帮助我做出此效果的一个属性:UIElement.OpacityMask属性。

    先来介绍一下UIElement.OpacityMask属性,它表示当前元素的不透明蒙版,该属性的值是Brush 类型,它能改变对象区域的不透明度的画笔,使元素的特定区域透明或部分透明,从而实现比较新颖的效果。值得一提的是,OpacityMask属性接受任何画刷,可利用LinearGradientBrush线性渐变画刷,通过对渐变画刷中各颜色点加以动画处理便能做出所需要的效果。

    渐变浮现效果,实现步骤:(1)通过事件触发器触发Loaded(加载)事件实现,直接在页面中去定义即可。

    (2)设置对象Border的OpacityMask属性:

    <Border Grid.Row="1" Grid.Column="1" BorderThickness="5" CornerRadius="5" Name="CloseBorder" Opacity="0.9" Background="#f1f1f1">
    <Border.OpacityMask>
                        <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                            <GradientStop Color="#00000000" Offset="0"/>
                            <GradientStop Color="#00000000" Offset="1"/>
                            <GradientStop Color="#00000000" Offset="1"/>
                        </LinearGradientBrush>
                    </Border.OpacityMask>
    </Border>
    

    (3)设置控件触发器Triggers:

    <Border.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                <DoubleAnimation From="1" To="0" Duration="0:0:1.5"             Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[1].Offset"/>
                <DoubleAnimation From="1" To="0" Duration="0:0:1" BeginTime="0:0:0.5"    Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[2].Offset"/>
                <ColorAnimation To="#FF000000" Duration="0"     Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[2].Color"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
    </Border.Triggers>
    

    用户点击退出时,Border渐隐效果:(1)通过为退出Button绑定Click事件,再到后端使用C#代码去实现此效果;

    (2)定义动画与画刷资源:

    <Window.Resources>
          <Storyboard x:Key="ClosedStoryBoard" Storyboard.TargetName="CloseBorder">
          <DoubleAnimation From="1" To="0" Duration="0:0:2" Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[1].Offset"/>
          <DoubleAnimation From="1" To="0" Duration="0:0:1.5" BeginTime="0:0:0.5"
    Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[2].Offset"/>
          <ColorAnimation To="#00000000" Duration="0" Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[2].Color"/>
    </Storyboard>
    <LinearGradientBrush x:Key="CloseBrush" StartPoint="0.5,0" EndPoint="0.5,1">
                <GradientStop Color="#FF000000" Offset="0"></GradientStop>
                <GradientStop Color="#FF000000" Offset="1"></GradientStop>
                <GradientStop Color="#FF000000" Offset="1"></GradientStop>
    </LinearGradientBrush>
    </Window.Resources>
    

    (3)后端通过绑定按钮的Click事件实现:

    <Button Grid.Column="3" Content="退出" x:Name="btnClose" Margin="20,0" Click="btnClose_Click" Style="{StaticResource LoginBtn}" FontFamily="微软雅黑">
    

    (4)C#后台事件代码:

     private void btnClose_Click(object sender, RoutedEventArgs e)
            {
                MessageBoxResult dr = MessageBox.Show("是否要退出系统?", "温馨提示",
                MessageBoxButton.OKCancel, MessageBoxImage.Question);
                //弹出确定对话框
                if (dr == MessageBoxResult.OK)
                {
                    //执行动画并关闭窗口
                    CloseBorder.OpacityMask = Resources["CloseBrush"] as LinearGradientBrush;
                    Storyboard std = Resources["ClosedStoryBoard"] as Storyboard;
                    std.Completed += delegate { Close(); };
                    std.Begin();
                }
            }
    
    展开全文
  • 嗯,好久没有写博客了,因为较长一段时间发生了点点变故:楼主从传统IT项目(OA)跳到了移动端,主要搞微信上...这里,楼主分两个模块从技术上讲解该功能,知道怎么做可以直接跳过第一部分。firstBlood,clip应用...

    嗯,好久没有写博客了,因为较长一段时间发生了点点变故:楼主从传统IT项目(OA)跳到了移动端,主要搞微信上的web开发,也是学习了很长一段时间。

    言归正传,微信上常见的手指滑动扣个圈圈,然后显示底层图片的应用相信大家也见过不少了。包括微信自身之前也出过付款看图片的应用,也是分分钟刷爆朋友圈。这里,楼主分两个模块从技术上讲解该功能,知道怎么做的可以直接跳过第一部分。

    firstBlood,clip的应用。

    var canvas = document.getElementById('canvas'),

    ctx = canvas.getContent('2d');

    ctx.save(); //先保存环境

    ctx.beginPath(); //开始路径

    ctx.arc(320, winH/2, 80, 0, Math.PI * 2, true); //根据一个坐标点,绘制一个半径为80的圆

    ctx.closePath(); //关闭路径

    ctx.clip(); //创建一个裁切路径

    ctx.clearRect(0, 0, 640, winH); //清除整个画布,由于之前已经clip过了,实际上只清除了圆的范围

    ctx.restore(); //还原环境

    通过这样一个操作,我们就可以在画布上口出一个半径为80的圆了。效果如下图:

    然后结合到各种touch事件,就可以做出擦除效果了,十分简单。

    secondBlood,PS画笔工具

    那么在该需求上做一下 衍生,PS的画笔工具相信大家也都用过,和前面的最大区别就在于圆的边缘会有一些模糊的效果。如果,需求到这里的话大可以通过canvas的createRadialGradient方法做一个渐变效果实现。接下来大家都懂的,需求远远不会那么简单,既然是做擦除效果,那么当两个圆相交的时候单凭渐变是无法实现该功能的。这个时候,canvas的像素操作技术就该登场咯,let go!

    以单次擦除范围为85像素的圆为准,思路如下:

    1,先扣除一个半径为55像素的小圆,参照 firstBlood的方法

    2,从55像素到85像素,做30次半径累加循环,每次循环都计算出 当前圆心和累加半径所构成的点,并依次增加点的透明度(这里每次循环透明度增加0.033)

    具体代码如下:

    function renderCanvas(){

    var empty = r - 30, curR, x = currentPos.x, y = currentPos.y, imgData, data, i, j, x1, y1, tempVal;

    ctx.save();

    ctx.beginPath();

    ctx.arc(x, y, empty, 0, Math.PI * 2, true);

    ctx.closePath();

    ctx.clip();

    ctx.clearRect(0, 0, 640, winH);

    ctx.restore();

    //清除了小圆后,获取整个canvas的像素点

    imgData = ctxTwo.getImageData(0, 0, 640, winH);

    //存储像素点 颜色值的一维数组

    data = imgData.data;

    for(i = 0; i < 30; i++) {

    curR = empty + i;

    for(j = 0; j < 361; j++) {

    //x1, y1代表当前半径上圆的点坐标

    x1 = parseInt(x + curR * Math.cos(j * Math.PI / 180));

    y1 = parseInt(y + curR * Math.sin(j * Math.PI / 180));

    //出范围了就继续

    if(x1 < 0 || y1 < 0 || x1 > 640 || y1 > winH) continue;

    //计算出一维数组中,当前点透明度的键值

    curPoint = (y1 - 1) * 640 * 4 + x1 * 4 + 3;

    //如果透明度已经是0了就不做处理

    if(0 == data[curPoint]) continue;

    //根据循环的半径做透明度降低处理

    tempVal = 255 * (i * 0.033);

    //如果计算出的透明度 高于当前的透明度就不做处理。

    if(tempVal < data[curPoint]) data[curPoint] = tempVal;

    }

    }

    //清楚整个画布

    ctx.clearRect(0, 0, 640, winH);

    //将处理过的像素值 在canvas上重绘

    ctx.putImageData(imgData, 0, 0);

    }

    效果如下:

    仔细看的话,会发现边缘会有模糊,当然这个范围可以增大 让其更明显。

    今天早上发现 android手机上也还是比较流畅特别是 锤子1手机,还是比较满意 O(∩_∩)O~

    关于像素点的计算,科普一下

    imgData = ctxTwo.getImageData(0, 0, 640, winH);

    imgData有一个名为data的一维数组 属性,以640 * 1008大小的canvas为例,

    其数组的长度为 640 * 1008 * 4,我们知道rgba的值为4位,前三位表示其rgba的值,第四位为其透明度的值,取值范围是0--255,

    我们反复强调data是一维数组,以第一个点为例,

    data[0],表示rgba的第一位

    data[1],表示rgba的第二位

    data[2],表示rgba的第三位

    data[3],表示其颜色的透明度

    如果我们要知道 230 * 150 这个点的颜色值的话,其在data里面的开始键值为:

    key = 229 * 640 * 4 + 150 * 4;

    那么对应的颜色值表示依次为

    data[key],表示rgba的第一位

    data[key + 1],表示rgba的第二位

    data[key + 2],表示rgba的第三位

    data[3 + 3],表示其颜色的透明度

    最后推荐一个canvas api手册网址:

    https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API

    相关术语以及专业的解释,案例都可以看到,谢谢!

    展开全文
  • MIUI12内测版在最近正式推送了,想必很多小米用户也第一时间上这新系统,也拿了MIUI12和iOS 13的动画来比较。今天阿狗我就仔细对比下两者的动画效果和细节,看看MIUI12的动画效果进步了多少吧。先来看解锁动画吧...

    MIUI12的内测版在最近正式推送了,想必很多小米用户也第一时间刷上这新系统,也拿了MIUI12和iOS 13的动画来比较。今天阿狗我就仔细对比下两者的动画效果和细节,看看MIUI12的动画效果进步了多少吧。

    先来看解锁动画吧。MIUI12的新功能超级壁纸,亮屏、解锁、进入桌面三个动作,动画刚好对应火星从远到近,从完全到部分,从宏观到微观。流畅性和创意都是足够的。在三个层级的到区分的同时,有做到了一体性。

    c387afd145db42acdcb851c2e7014e1b.gif

    而iOS 13的动画则要简单不少。亮屏、解锁、进入桌面三个动作,就像是开灯、推开盖子、进去。它更像是在一个理性的物理世界中,没有特别花哨的玩法,但符合我们对世界的认知。不少网友吐槽说,MIUI12的解锁动画是不是太长了,让人觉得有点拖沓。仔细看,实际上MIUI12从解锁到进入桌面的时间,跟iOS 13是非常接近的。只是进入桌面后,动态壁纸还在继续运动而已。

    c6e138ee5fbfeb92b94c24bb8fa05ee7.gif

    不过我更想说的是,解锁进入桌面的这个动画。它的过程是先缩小,看到火星的大半部分,之后绕火星旋转并加速放大。缩小和放大这两个动画效果,其实是有一点破坏解锁动画一体性的。火星的超级壁纸动画,我的理解是从太空降落到火星的过程。如果改为通过旋转加上持续放大,最后到指定地点,这样可能会更像降落火星。不过MIUI的团队可能有自己的想法,这里也欢迎各位机佬一起讨论下。接下来是APP的打开动画。正常的竖屏APP在打开的时候,APP界面的圆角刚好跟屏幕边缘的圆角对应弧度是对应的,没有明显锯齿感。这点跟iOS的App打开动画一样优秀,必须好评。不过需要注意的是,底部的小横条没有做沉浸式设计,有点破坏整个动画的美感。

    4a09e0ca7b21bf1d1c927f5f819ea713.gif

    而从APP回到桌面的过程,也是遵循从哪里来就回到哪里的原则。从界面到图标整个过程也符合小凡在发布会上说的物理曲线感觉。打开程序时像是一个东西张开了,而回到桌面就像它被收了回来。符合物理世界的直觉。

    过需要吐槽的一点是,由于MIUI图标的不规则性,所以导致图标动画从圆角到不规则图标时有些突兀。后续通过图标的调整换成圆角图标可能会更统一一些。

    另一方面,打开APP的过程中,状态栏的时间部分先是做了渐隐的动画效果,然后再到状态栏的全局渐隐。这个动画不是特别统一,有点奇怪。之后是系统功能的动画。MIUI12和iOS 13的动画效果相比,各个通知信息在下滑的时候像是一块块海绵的落下。而iOS 13由于通知栏跟锁屏界面是属于同一个层级,动画效果像关上一个抽屉,呼应了解锁时动画。就动画效果而言,MIUI12更具动感和灵性,线性动画的感知也更明显。

    2902404dabec6fecb678f30453f65319.gif

    控制中心界面,MIUI12和iOS 13的动画也是类似的。MIUI12将通知栏的动画风格也应用到了控制中心界面,视觉上也比较统一对称。

    fecca06d5e3eba983c3e1fb32dcd162a.gif

    在开启后台多任务的部分,MIUI12和iOS 13是两种不同的风格。起始动画上,两个系统都是桌面先下沉,毛玻璃效果覆盖。之后后台程序像摆放好的文件一样出现。两个系统后台APP窗口的圆角一样是保持了和屏幕圆角一样的弧度,这点给好评。MIUI因为是选择了平铺式的后台应用界面,因此还有一个像扑克牌发牌一样的动画效果,这种过渡细节也做得非常不错。

    772c6ea0881718c9f4ad512451f4da10.gif

    切换应用方面,MIUI12和iOS 13差别不是特别大。后台应用界面的圆角一样和屏幕圆角一致。但是,当我在做应用到应用的切换时,顶部状态栏的图标就出现差异了。iOS 13在应用切换的过程中,将时间、电量这些状态栏信息做了渐隐处理,等下一个应用成功切换时,这些信息会重新渐变出现。而MIUI12则有点反应上的迟钝。切换应用时状态栏图标没用跟随动画效果发生改变,一直停留在状态栏。当应用成功切换时,它就做了一个从上往下的滑动动画,刷了一下存在感。

    b4ba6e2da618c4a48475850a3e7190f1.gif

    旋转屏幕的动画效果上,MIUI12也做到了和iOS 13一样流畅的屏幕旋转效果。

    4b84b4ed0c5c10026d69ef5dec6a9f85.gif

    删除应用方面,iOS 13选择了以缩小至消失的动画效果,而MIUI12则是"灭霸"的粉碎效果。两者一样是风格上的不同,看个人喜好。

    抠了不少MIUI12的动画细节了,可以看出来小米这次在动画效果上确实是花了很多的心思。MIUI12的核心理念是"触碰想象,感受真实"。就目前内测版的实际效果来说,我觉得已经实现这个目标了,物理动画引擎确实接近iOS的系统水准。这点我觉得不会有多少用户有异议。不过因为内测版本,有些小问题比如掉帧、一些系统元素的错位,这些希望在公测版上可以得到改善。MIUI12给了我们一个希望,就就是安卓的系统动画真要做起来,不会比苹果的差。加上高刷新率的优势,我相信后面会有更多的用户愿意接受安卓手机,打破以前留在脑海的固有印象。

    展开全文
  • 这里实现了以下功能:随着收到 IM 礼物消息,实时累加礼物数量如果超出连击时间,比如 3s ,则重新开始计数,从 1 开始如果在连击时间内,则在原先基础上累加下面把改造思路跟大家分享下:问题一:之前动画已经把...
  • 关键词:windows7 IE8 任务栏 出现 IE8图标    使用IE8的时候,如果鼠标滑动到flash动画或者视频播放器上时,底部的任务栏会出现一个IE的图标。... 我就是去掉了“在Flash和流媒体上显示下载图标”的功能后,
  • 完全没有canvas基础同学建议先一下<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Basic_usage">Canvas基本用法 - Web API 接口参考 | MDN</a></p> 重点是理解canvas动画的...
  • 本文实例讲述了微信小程序列表渲染功能之列表下拉刷新及上拉加载实现方法。分享给大家供大家参考,具体如下: 微信小程序为2017年1月9日打下了一个特殊标签,迅速爆了网络和朋友圈,最近我也写了一个demo程序...
  • 前言 小程序上线爆了朋友圈,...下面介绍一下我制作小程序完成的几个小的功能,希望能够给开发小程序的朋友带来帮助! 滚动动画制作 小程序制作回到顶部,或者滚动到某个位置,很简单,也有很多实现方法...
  • 竟然还能用来制作H5 最近几年随着移动端快速发展,我们获取信息途径更加便捷了,我们几乎每天都会微博、看朋友圈。而在众多信息传递中,H5页面成了最受大众欢迎形式。所谓H5,简单来看就是那种打开之后...
  • 网页时候,有时会遇到这样一个情景,当某个dom元素滚到可见区域时,它就会展现显示动画,十分有趣。那么这是如何实现呢? 实现原理 想要实现这个功能,就要知道具体实现原理。下面直入主题。 我们通过...
  • 我是在pad上用,下面截图都是pad尺寸,手机版我也下了,内部功能操作界面都一样。界面如下,像素画基本工具都有,铅笔,吸色,橡皮,选区,油漆桶,刷子,形状,文字等等,还有一些我还不知道干嘛工具,还...
  • 早上好~胖友们为了更好帮助大家提升互动创意排版技巧今天三儿给大家带来公众号文章SVG样式一些小技巧及注意事项1... 用专业版动画功能3. 在代码里修改对应文字2️⃣svg设置好点击查看内容后,为什么预览...
  • 这是那个时候再要上选择工具或技术。 如果你觉得你一直在努力,在建设,但也许... DevTools挑战者 一个互动网站,演示了如何使用新的动画相关的功能出现在Firefox开发版。 2. HTML和CSS做工手册 一个良好的HTML ...
  • 90后主要是通过视频获取信息、娱乐一代,各大主流在线视频播放器都实现了弹幕功能,并且我们用还乐此不疲,真挺好玩。  通过代码来实现弹幕思路:在数据库读取信息,显示在界面上。这个界面是弹幕样式...
  • 支持的功能: 横向或竖向滑动 循环翻页 总体和页面等级过渡效果 页面等级禁止滑动 外部API调用 完善的事件机制 可扩展的过渡动画 文件 基本用法 只需三步即可完成: ♡js和css,可以按照以下两种方式之一进行: 在...
  • 建模进度2

    2017-05-13 22:21:43
    不得不说CS骨骼系统非常强大,各种逆天的功能完爆自带的bone骨骼。 高模的权重是一件 制作动画的话绑骨是一个很重要的过程。 像撸主一样低配电脑的看官们最好不要执着于高模的权重了,真的出问题的时候,不但您...
  • ZrcListView

    2016-03-25 22:12:18
    ZrcListView一个顺滑又...2.增加自定义列表项动画的功能; 与其他下拉刷新列表组件的不同1.其他下拉刷新组件的实现基本是通过动态更改Header的大小来实现的,而ZrcListView是修改了Listview的边界判断; 2.其他下拉
  • flash shiti

    2014-03-14 10:32:41
    35.Flash5允许使用Action的功能有哪几种? A. Symbol B. Movie Clips C. Keyframe D. Button Symbol 36.以下语句说法正确的有: A. getURL表示使浏览器浏览到指定页面 B. gotoAndPlay表示跳转到指定帧并播放 ...
  • Coolui Scroll基于小程序原生组件scroll-view上拉加载下拉功能强大,文档清晰,基本满足了大部分小程序下拉刷新场景需求。一起看案例。 ❞ 前言 基于小程序原生组件scroll-view扩展与封装,实现简单上拉...
  • DragonFace也就是全志固件修改工具,支持全志H2 H3 H8 A31 A20 A21 A10系列安卓全部固件,他是一款高效的固件修改工具,如固件版本信息、产品型号、公司名称等等。...还有更多强大的功能在等待着您去挖掘!
  • -DOTween是一种适用于Unity快速,高效,完全类型安全面向对象的动画引擎,针对C#用户进行了优化(免费和开源),并具有大量高级功能 作者 安德烈·卡多佐( 米克 执照 此项目已获得MIT许可证许可-有关详细...
  • 如何判断指定dom元素是否在屏幕内

    千次阅读 2016-10-17 13:35:54
    网页时候,有时会遇到这样一个情景,当某个dom元素滚到可见区域时,它就会展现显示动画,十分有趣。那么这是如何实现呢?实现原理想要实现这个功能,就要知道具体实现原理。下面直入主题。 我们通过浏览器...
  • 胖友们大家好啊,我是三儿作为一个合格新媒体人怎么能不掌握几款滑动样式呢其实...【使用说明】:可通过更改代码或者动画功能进行增减图片设置。一般样式都可以秒使用,先插入图片写好文字然后点击样式秒,...
  • 固件修改工具(DragonFace)是一个高效的固件修改——功能强大、所见即所得、操作便易的工具。 只要是用于在某个发布固件中修改OEM 厂家客户的需求,如固件版本信息、产品型号...还有更多强大的功能在等待着您去挖掘!
  • 追随者-源码

    2021-02-17 08:56:55
    一些功能是相同: UI元素和布局(主屏幕,关注者屏幕,收藏夹屏幕) 其他是新: 热门流屏幕 直播频道徽章+动画 应用流程 实时频道信息(用户信息屏幕) 使用新Twitch API 主屏幕 用户可以在此处通过其...

空空如也

空空如也

1 2 3 4
收藏数 69
精华内容 27
关键字:

动画刷的功能是