自定义view实现阻尼效果的加载动画

效果:

>

需要知识:

1. 二次贝塞尔曲线

2. 动画知识

3. 基础自定义view知识

先来解释下什么叫阻尼运动

阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动、衰减振动。[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来。这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运动.阻尼振动系统属于耗散系统。这里的阻尼是指任何振动系统在振动中,由于外界作用或系统本身固有的原因引起的振动幅度逐渐下降的特性,以及此一特性的量化表征。

本例中文字部分凹陷就是这种效果,当然这篇文章知识带你简单的使用.

跳动的水果效果实现

剖析:从上面的效果图中很面就是从顶端向下掉落然后再向上 期间旋转即可.

那么我们首先自定义一个view继承FrameLayout

public class My extends FrameLayout {

    public My(Context context) {
        super(context);
    }

    public My(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

}

需要素材如下三张图片:

也许有人会问我看到你效果图到顶部或者底部就变成向上或者向下了.你三张够吗?

答:到顶部或者底部旋转180度即可

我们现在自定义中定义几个变量


    //用于记录当前图片使用数组中的哪张
    int indexImgFlag = 0;

    //下沉图片 前面三个图片的id
    int allImgDown [] = {R.mipmap.p2,R.mipmap.p4,R.mipmap.p6,R.mipmap.p8};

    //动画效果一次下沉或上弹的时间 animationDuration*2=一次完整动画时间
    int animationDuration = 1000;

    //弹起来的图片
    ImageView iv;

    //图片下沉高度(即从最高点到最低点的距离)
    int downHeight = 2;
    //掉下去的动画
    private Animation translateDown;
    //弹起动画
    private Animation translateUp;
    //旋转动画
    private ObjectAnimator rotation;

我们再来看看初始化动画的方法(此方法使用了递归思想,实现无限播放动画,大家可以看看哪里不理解)

 //初始化弹跳动画
    public void  MyAnmation(){
        //下沉效果动画
        translateDown = new TranslateAnimation(
                Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0,
                Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,downHeight);
        translateDown.setDuration(animationDuration);
        //设置一个插值器 动画将会播放越来越快 模拟重力
        translateDown.setInterpolator(new AccelerateInterpolator());

        //上弹动画
        translateUp = new TranslateAnimation(
         Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0,
          Animation.RELATIVE_TO_SELF,downHeight,Animation.RELATIVE_TO_SELF,0
       );

        translateUp.setDuration(animationDuration);
        ////设置一个插值器 动画将会播放越来越慢 模拟反重力
        translateUp.setInterpolator(new DecelerateInterpolator());

        //当下沉动画完成时播放启动上弹
        translateDown.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                iv.setImageResource(allImgDown[indexImgFlag]);
                rotation = ObjectAnimator.ofFloat(iv, "rotation", 180f, 360f);
                rotation.setDuration(1000);
                rotation.start();
            }

            @Override
            public void onAnimationEnd(Animation animation) {

                iv.startAnimation(translateUp);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        //当上移动画完成时 播放下移动画
        translateUp.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                indexImgFlag = 1+indexImgFlag>=allImgDown.length?0:1+indexImgFlag;
                iv.setImageResource(allImgDown[indexImgFlag]);
                rotation = ObjectAnimator.ofFloat(iv, "rotation", 0.0f, 180f);
                rotation.setDuration(1000);

                rotation.start();
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //递归
                iv.startAnimation(translateDown);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

以上代码知识:

插值器:会让一个动画在播放时在某一时间段加快动画或者减慢

//设置一个插值器 动画将会播放越来越快 模拟重力

1. translateDown.setInterpolator(new AccelerateInterpolator());

这个插值器 速率表示图:

可以从斜率看到使用此插值器 动画将越来越快.意义在于模仿下落时重力的影响

////设置一个插值器 动画将会播放越来越慢 模拟反重力

2. translateUp.setInterpolator(new DecelerateInterpolator());

速率图:

最后我们初始化下图片控件到我们的自定义view

private void init() {

    //初始化弹跳图片 控件
    iv = new ImageView(getContext());

    ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);

    iv.setLayoutParams(params);
    iv.setImageResource(allImgDown[0]);

    this.addView(iv);

    iv.measure(0,0);

    iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            if (!flagMeure)
            {
                flagMeure =true;
                //由于画文字是由基准线开始
                path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());

                //计算最大弹力
                maxElasticFactor = (float) (textHeight / elastic);
                //初始化贝塞尔曲线
                path.rQuadTo(textWidth / 2, 0, textWidth, 0);

                //初始化上弹和下沉动画
                MyAnmation();

                iv.startAnimation(translateDown);
            }
        }
    });

}

上面的知识:

1. iv.measure(0,0);主动通知系统去测量此控件 不然iv.getwidth = 0;

//下面这个是同理 等iv测量完时回调 不然iv.getwidth = 0;

2. iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){

}

原因:TextView tv = new TextView() 或者 LayoutInflat 填充布局都是

异步所以你在new出来或者填充时直接获取自然返回0

到现在为止你只需要在自定义view 的onSizeChanged回调方法中调用init()即可看到动画的弹动

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        init();
    }

此方法会在onmesure方法执行完成后回调 这样你就可以在此方法获得自定义view的宽高了

效果图:


画文字成u形

首先你得知道如下知识

贝塞尔曲线:具体学习

这里我们用到2此贝塞尔曲线

我们看看大概是什么叫2次贝塞尔曲线

我们看看 三个点 p0 p1 p2 我们 把p0 称为 开始点 p1 为控制点 p2 结束点,那么可以用贝塞尔公式画出如图曲线

这里大家没必要深究怎么画出来. 也不需要你懂 这个要数学基础的

那么我们在安卓中怎么画呢?

 Path path = new Path();
//p0的x y坐标
path.moveTo(p0.x,y);
path.rQuadTo(p1.x,p1.y,p2.x,p2.y);

这就是API调用方法是不是很简单?那么你又会问那么怎么画出来呢?

很简单在 dispatchDraw方法 或者onDraw中 调用

  @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.drawPath(path,paint);
    }

那么你画出来的效果应该和在Ps用钢笔画出来的差不多 ps中钢笔工具就是二次贝塞尔曲线

(借用下图片)

如果你的三个点的位置如刚开的图片 p0 p1 p2 (p1在p0右上方并且 p1在p2左上方)一样那么在屏幕中的显示效果如下

这里随扩张下dispatchDraw和ondraw的区别

如果你的自定义view 是继承view 那么 会先调用 ondraw->>dispatchDraw

如果你的自定义view 是继承viewgroup那么会跳过ondraw方法直接调用dispathchDraw这里特别注意!!我们这个案例中继承的是FrameLayout,

而frameLayout又是继承自viewgroup所以….

那么我们回到主题 如何画一个U形文字?简单就是说按照我们画出来的曲线在上面写字 如: 文字是”CSDN开源中国” 如何让这几个字贴着我们的曲线写出来?

这里介绍一个API

canvas.drawTextOnPath()

第一个参数:文字 类型为字符串

第二个参数:路径 也就是我们前面的二次贝塞尔曲线

第三个参数:沿着路径文字开始的位置 说白了偏移量

第四个参数:贴着路径的高度的偏移量

hOffset:

The distance along the path to add to the text’s starting position

vOffset:

The distance above(-) or below(+) the path to position the text

//ok我们看看他可以画出什么样子的文字

这种看大家对贝塞尔曲线的理解,你理解的越深那么你可以画出的图像越多,当然不一定要用贝塞尔曲线


确定贝塞尔曲线的起点

我们在回过头来看看我们的效果图

我们可以看到文字应该是在iv(弹跳的图片中央位置且正好在 iv弹到底部的位置)

这里我们先补充知识在考虑计算

我们来学习一下文字的测量我们来看幅图

我们调用画文字的API时

canvas.drawTextOnPath或者canvas.drawText 是从基准线开始画的也就是说途中的baseline开始画.

如:

canvas.drawText(“FMY”,0,0,paint);

那么你将看不到文字 只能在屏幕看到文字底部如下图:

另一个同理API drawTextOnPath 也是

再看看几个简单的API

1 . paint.measureText(“FMY”);返回在此画笔paint下写FMY文字的宽度

下面的API会把文字的距离左边left 上边top 右边right 底部的bottom的值写入此矩形 那么

rect.right-rect.left=文字宽度

rect.bottom-rect.top=文字高度

  //矩形
 Rect   rect = new Rect();
 //将文字画入矩形目的是为了测量高度
 paint.getTextBounds(printText, 0, printText.length(), rect);

那么请看:

 private void init() {

        //初始化弹跳图片 控件
        iv = new ImageView(getContext());

        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);

        iv.setLayoutParams(params);
        iv.setImageResource(allImgDown[0]);

        this.addView(iv);

        //画笔的初始化
        paint = new Paint();
        paint.setStrokeWidth(1);
        paint.setColor(Color.CYAN);
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(50);
        paint.setAntiAlias(true);

        //矩形
     Rect   rect = new Rect();
        //将文字画入矩形目的是为了测量高度
        paint.getTextBounds(printText, 0, printText.length(), rect);

        //文本宽度
        textWidth = paint.measureText(printText);

        //获得文字高度
        textHeight = rect.bottom - rect.top;

        //初始化路径
        path = new Path();

        iv.setX(getWidth()/2);

        iv.measure(0,0);

        iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                if (!flagMeure)
                {
                    flagMeure =true;

                    //由于画文字是由基准线开始
                    path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());

                    //计算最大弹力
                    maxElasticFactor = (float) (textHeight / elastic);
                    //初始化贝塞尔曲线
                    path.rQuadTo(textWidth / 2, 0, textWidth, 0);

                    //初始化上弹和下沉动画
                    MyAnmation();

                    iv.startAnimation(translateDown);
                }
            }
        });

    }

我们现在写一个类当iv图片(弹跳图)碰到文字顶部时设置一个监听器 时间正好是弹图向上到顶部的时间 期间不断让文字凹陷在恢复正常

  //用于播放文字下沉和上浮动画传入的数值必须是 图片下沉和上升的一次时间
    public void initAnimation(int duration){
        //这里为什maxElasticFactor/4 好看...另一个同理 这个数值大家自行调整
        ValueAnimator animator =  ValueAnimator.ofFloat(maxElasticFactor/4, (float) (maxElasticFactor / 1.5),0);
        animator.setDuration(duration/2);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                calc();//重新画路径
                nowElasticFactor= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }

再来一个重新绘画路径计算的方法

   public void calc(){

        //重置路径
        path.reset();
        //由于画文字是由基准线开始
        path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());
        //画二次贝塞尔曲线
        path.rQuadTo(textWidth / 2, nowElasticFactor, textWidth, 0);

    }

好了到这里我们看看完整源码吧:

package com.example.administrator.myapplication;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class My extends FrameLayout {

    //画笔
    private Paint paint;
    //路径
    private Path path;
    //要输入的文本
    private String printText = "正在加载";
    //文本宽
    private float textWidth;
    //文本高
    private float textHeight;
    //测量文字宽高的时候使用的矩形
    private Rect rect;
    //最大弹力系数
    private float elastic = 1.5f;

    //最大弹力
    private float maxElasticFactor;

    //当前弹力
    private float nowElasticFactor;

    //用于记录当前图片使用数组中的哪张
    int indexImgFlag = 0;

    //下沉图片
    int allImgDown [] = {R.mipmap.p2,R.mipmap.p4,R.mipmap.p6,R.mipmap.p8};

    //动画效果一次下沉或上弹的时间 animationDuration*2=一次完整动画时间
    int animationDuration = 1000;

    //弹起来的图片
    ImageView iv;

    //图片下沉高度(即从最高点到最低点的距离)
    int downHeight = 2;
    private Animation translateDown;
    private Animation translateUp;

    private ObjectAnimator rotation;

    public My(Context context) {
        super(context);
    }

    public My(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.drawTextOnPath(printText, path, 0, 0, paint);
    }

    //用于播放文字下沉和上浮动画传入的数值必须是 图片下沉和上升的一次时间
    public void initAnimation(int duration){
        //这里为什maxElasticFactor/4为什么
        ValueAnimator animator =  ValueAnimator.ofFloat(maxElasticFactor/4, (float) (maxElasticFactor / 1.5),0);
        animator.setDuration(duration/2);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                calc();
                nowElasticFactor= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }

    public void calc(){

        //重置路径
        path.reset();
        //由于画文字是由基准线开始
        path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());
        //画二次贝塞尔曲线
        path.rQuadTo(textWidth / 2, nowElasticFactor, textWidth, 0);

    }

    //初始化弹跳动画
    public void  MyAnmation(){
        //下沉效果动画
        translateDown = new TranslateAnimation(
                Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0,
                Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,downHeight);
        translateDown.setDuration(animationDuration);
        //设置一个插值器 动画将会播放越来越快 模拟重力
        translateDown.setInterpolator(new AccelerateInterpolator());

        //上弹动画
        translateUp = new TranslateAnimation(
         Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0,
          Animation.RELATIVE_TO_SELF,downHeight,Animation.RELATIVE_TO_SELF,0
       );

        translateUp.setDuration(animationDuration);
        ////设置一个插值器 动画将会播放越来越慢 模拟反重力
        translateUp.setInterpolator(new DecelerateInterpolator());

        //当下沉动画完成时播放启动上弹
        translateDown.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                iv.setImageResource(allImgDown[indexImgFlag]);
                rotation = ObjectAnimator.ofFloat(iv, "rotation", 180f, 360f);
                rotation.setDuration(1000);
                rotation.start();
            }

            @Override
            public void onAnimationEnd(Animation animation) {

                iv.startAnimation(translateUp);
                initAnimation(animationDuration);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        //当上移动画完成时 播放下移动画
        translateUp.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                indexImgFlag = 1+indexImgFlag>=allImgDown.length?0:1+indexImgFlag;
                iv.setImageResource(allImgDown[indexImgFlag]);
                rotation = ObjectAnimator.ofFloat(iv, "rotation", 0.0f, 180f);
                rotation.setDuration(1000);

                rotation.start();
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //递归
                iv.startAnimation(translateDown);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

    }

    boolean flagMeure;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        init();
    }

    private void init() {

        //初始化弹跳图片 控件
        iv = new ImageView(getContext());

        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);

        iv.setLayoutParams(params);
        iv.setImageResource(allImgDown[0]);

        this.addView(iv);

        //画笔的初始化
        paint = new Paint();
        paint.setStrokeWidth(1);
        paint.setColor(Color.CYAN);
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(50);
        paint.setAntiAlias(true);

        //矩形
        rect = new Rect();
        //将文字画入矩形目的是为了测量高度
        paint.getTextBounds(printText, 0, printText.length(), rect);

        //文本宽度
        textWidth = paint.measureText(printText);

        //获得文字高度
        textHeight = rect.bottom - rect.top;

        //初始化路径
        path = new Path();

        iv.setX(getWidth()/2);

        iv.measure(0,0);

        iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                if (!flagMeure)
                {
                    flagMeure =true;
                    //由于画文字是由基准线开始
                    path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());

                    //计算最大弹力
                    maxElasticFactor = (float) (textHeight / elastic);
                    //初始化贝塞尔曲线
                    path.rQuadTo(textWidth / 2, 0, textWidth, 0);

                    //初始化上弹和下沉动画
                    MyAnmation();

                    iv.startAnimation(translateDown);
                }
            }
        });

    }
}

小人奉上源码一封供大家 参考github源码下载地址

时间: 2024-11-06 14:31:39

自定义view实现阻尼效果的加载动画的相关文章

自定义View基础之——图片加载进度条

学会了Paint,Canvas的基本用法之后,我们就可以动手开始实践了,先写个简单的图片加载进度条看看. 按照惯例,先看效果图,再决定要不要往下看: 既然看到这里了,应该是想了解这个图片加载进度条了,我们先看具体用法,再看自定义View的实现: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.co

【Android自定义View实战】之仿百度加载动画,一种优雅的Loading方式

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53470872 本文出自[DylanAndroid的博客] Android自定义View实战之仿百度加载动画一种优雅的Loading方式 第一个仿百度加载动画用ObjectAnimator属性动画操作ImageView的属性方法实现 第二个仿百度加载动画第二种实现方式用ValueAnimator原生的ondraw方法实现 第三个扔球动画-水平旋转动画 第四个扔球动画-垂直旋转动

自定义progressdialog加载动画,这里还有旋转的加载条,美团,多个图片动画

下载Demo:http://download.csdn.net/detail/menglele1314/8775497 public class MainActivity extends Activity { private Button submit; private AnimationDrawable fightnimation, fightnimationab; private ImageView pb, net, netab; private Dialog mLoading; priva

使用MJRefresh自定义下拉刷新,上拉加载动画

有时候我们需要自己设置下拉刷新,上拉加载动画的实现,这里主要是记录下使用MJRefresh自定义下拉刷新,上拉加载动画..... 下拉刷新我们只需要继承MJRefreshGifHeader即可: 实现代码如下: - (void)prepare{ [super prepare]; self.stateLabel.hidden = NO; self.lastUpdatedTimeLabel.hidden = YES; [self setImages:@[[UIImage imageNamed:@"v

Android实战页面内容加载动画

前言 文章开头来看一下本篇文章要实现的效果,如图 左边是慕课网APP中的效果,右边是58同城APP中的加载动画. 实现第一种动画 之前用图形的混合模式和贝塞尔曲线实现过慕课网的下拉刷新的加载动画.见链接慕课网app下拉刷新图标填充效果的实现,而这种动画效果在app中其实也很常见,之前的那篇文章是自定义View绘制出来的,其实这个也可以用DrawableAnimation实现,这里,我们来实现一下,看看有多简单.首先提取图片资源,图片提取自慕课网App,如图. 提取完图片之后就是编写Drawabl

iOS开发——图形编程Swift篇&amp;CAShapeLayer实现圆形图片加载动画

CAShapeLayer实现圆形图片加载动画 几个星期之前,Michael Villar在Motion试验中创建一个非常有趣的加载动画. 下面的GIF图片展示这个加载动画,它将一个圆形进度指示器和圆形渐现动画结合.这个组合的效果有趣,独一无二和有点迷人. 这个教程将会教你如何使用Swift和Core Animatoin来重新创建这个效果.让我们开始吧! 基础 首先下载这个教程的启动项目,然后编译和运行.过一会之后,你应该看到一个简单的image显示: 这 个启动项目已经预先在恰当的位置将view

仿慕课网下拉加载动画

最近在做动画的项目,在eoe看了篇帖子,然就试着做了一下仿慕课网的下来加载动画. 毕竟我看到的那篇帖子里,没有附上源码.于是自己用ps了下图标:实现了之后其实也挺简单,就是AnimationDrawable类进行 Animation-list中item的循环遍历图片,类似于flash里的帧帧动画 接下来就先附上源码,相信大家都容易看的懂: 这里为了 让这个动画效果可被复用,于是就继承了 ImageView 去实现某些方法 1 package com.example.loading_drawabl

超酷jQuery进度条加载动画集合

在丰富多彩的网页世界中,进度条加载动画的形式非常多样,有利用gif图片实现的loading动画,也有利用jQuery和CSS3实现的进度加载动画,本文主要向大家介绍很多jQuery和CSS3实现的进度条加载动画,每一个都非常具有创意.如果你喜欢,可以下载源码并将它们应用到自己的网站中去. HTML5 Canvas发光Loading动画 它是一个Loading加载动画,并不能实现具体进度的加载,但是可以提示用户数据或者页面正在加载.并且该应用利用Canvas绘制动画,效果非常不错. DEMO演示 

图片加载动画

项目中用到了调用前置摄像头的功能,然后拍出来的照片需要处理后才能让人脸朝上.刚开始我用重力感应去判断手机当时的方向,效果很好,不管手机是横放还是竖放,拍出来的照片始终是头朝上的,然而有一部手机在测试的时候出现了bug,只要使用了重力感应退出去的时候就会崩溃.后来将重力感应关闭后就不再崩溃了.重力感应是iOS4.0之前的方法,iOS5.0后用coremotion代替了重力感应,这种框架也能够监听手机的状态,然而我发现还是会崩溃,不过很难重现,于是准备放弃这种方法.毕竟只要出现一次崩溃就说明代码有问