Android动画进阶—使用开源动画库nineoldandroids

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17639987

前言

Android系统支持原生动画,这为应用开发者开发绚丽的界面提供了极大的方便,有时候动画是很必要的,当你想做一个滑动的特效的时候,如果苦思冥想都搞不定,那么你可以考虑下动画,说不定动画轻易就搞定了。下面再简单回顾下Android中的动画,本文后面会介绍一个稍微复杂点的动画,先上效果图


动画分类

View动画:也叫渐变动画,针对View的动画,主要支持平移、旋转、缩放、透明度

Drawable动画:也叫帧动画,主要是设置View的背景,可以以动画的形式为View设置多张背景

对象属性动画(Android3.0新加入):可以对对象的属性进行动画而不仅仅是View,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对象从一个属性值到另一个属性值的改变,因此,属性动画几乎是无所不能的,只要对象有这个属性,它都能实现动画效果,但是属性动画从Android3.0才有,这就严重制约了属性动画的使用,这就是开源动画库nineoldandroids的作用,采用nineoldandroids,可以在3.0以前的系统上使用属性动画,nineoldandroids的网址是:http://nineoldandroids.com。说到属性动画,就不得不提到插值器(TimeInterpolator)和估值算法(TypeEvaluator),下面介绍。

TimeInterpolator和TypeEvaluator

TimeInterpolator中文翻译为时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢中间快)和DecelerateInterpolator(减速插值器:动画越来越慢)等;TypeEvaluator的中文翻译为类型估值算法,它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)和ArgbEvaluator(针对Color属性)。可能这么说还有点晦涩,没关系,下面给出一个实例就很好理解了。


看上述动画,很显然上述动画是一个匀速动画,其采用了线性插值器和整型估值算法,在40ms内,View的x属性实现从0到40的变换,由于动画的默认刷新率为10ms/帧,所以该动画将分5帧进行,我们来考虑第三帧(x=20 t=20ms),当时间t=20ms的时候,时间流逝的百分比是0.5 (20/40=0.5),意味这现在时间过了一半,那x应该改变多少呢,这个就由插值器和估值算法来确定。拿线性插值器来说,当时间流逝一半的时候,x的变换也应该是一半,即x的改变是0.5,为什么呢?因为它是线性插值器,是实现匀速动画的,下面看它的源码:

public class LinearInterpolator implements Interpolator {    public LinearInterpolator() {    }        public LinearInterpolator(Context context, AttributeSet attrs) {    }        public float getInterpolation(float input) {        return input;    }}

很显然,线性插值器的返回值和输入值一样,因此插值器返回的值是0.5,这意味着x的改变是0.5,这个时候插值器的工作就完成了。

具体x变成了什么值,这个需要估值算法来确定,我们来看看整型估值算法的源码:

public class IntEvaluator implements TypeEvaluator<Integer> {    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {        int startInt = startValue;        return (int)(startInt + fraction * (endValue - startInt));    }}

上述算法很简单,evaluate的三个参数分别表示:估值小数、开始值和结束值,对应于我们的例子就分别是:0.5,0,40。根据上述算法,整型估值返回给我们的结果是20,这就是(x=20 t=20ms)的由来。

说明:属性动画要求该属性有set方法和get方法(可选);插值器和估值算法除了系统提供的外,我们还可以自定义,实现方式也很简单,因为插值器和估值算法都是一个接口,且内部都只有一个方法,我们只要派生一个类实现接口就可以了,然后你就可以做出千奇百怪的动画效果。具体一点就是:自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值算法需要实现TypeEvaluator。还有就是如果你对其他类型(非int、float、color)做动画,你必须要自定义类型估值算法。

nineoldandroids介绍

其功能和android.animation.*中的类的功能完全一致,使用方法完全一样,只要我们用nineoldandroids来编写动画,就可以在所有的Android系统上运行。比较常用的几个动画类是:ValueAnimator、ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集,可以定义一组动画。使用起来也是及其简单的,下面举几个小栗子。

栗子1:改变一个对象(myObject)的 translationY属性,让其沿着Y轴向上平移一段距离:它的高度,该动画在默认时间内完成,动画的完成时间是可以定义的,想要更灵活的效果我们还可以定义插值器和估值算法,但是一般来说我们不需要自定义,系统已经预置了一些,能够满足常用的动画。

ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();

栗子2:改变一个对象的背景色属性,典型的情形是改变View的背景色,下面的动画可以让背景色在3秒内实现从0xFFFF8080到0xFF8080FF的渐变,并且动画会无限循环而且会有反转的效果

ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF);colorAnim.setDuration(3000);colorAnim.setEvaluator(new ArgbEvaluator());colorAnim.setRepeatCount(ValueAnimator.INFINITE);colorAnim.setRepeatMode(ValueAnimator.REVERSE);colorAnim.start();

栗子3:动画集合,5秒内对View的旋转、平移、缩放和透明度都进行了改变

AnimatorSet set = new AnimatorSet();set.playTogether(    ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),    ObjectAnimator.ofFloat(myView, "rotationY", 0, 180),    ObjectAnimator.ofFloat(myView, "rotation", 0, -90),    ObjectAnimator.ofFloat(myView, "translationX", 0, 90),    ObjectAnimator.ofFloat(myView, "translationY", 0, 90),    ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f),    ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f),    ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1));set.setDuration(5 * 1000).start();

栗子4:下面是个简单的调用方式,其animate方法是nineoldandroids特有的

Button myButton = (Button)findViewById(R.id.myButton);//Note: in order to use the ViewPropertyAnimator like this add the following import://  import static com.nineoldandroids.view.ViewPropertyAnimator.animate;animate(myButton).setDuration(2000).rotationYBy(720).x(100).y(100);

栗子5:一个采用nineoldandroids实现的稍微复杂点的动画

布局xml如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <Button        android:id="@+id/menu"        style="@style/MenuStyle"        android:background="@drawable/menu" />    <Button        android:id="@+id/item1"        style="@style/MenuItemStyle"        android:background="@drawable/circle1"        android:visibility="gone" />    <Button        android:id="@+id/item2"        style="@style/MenuItemStyle"        android:background="@drawable/circle2"        android:visibility="gone" />    <Button        android:id="@+id/item3"        style="@style/MenuItemStyle"        android:background="@drawable/circle3"        android:visibility="gone" />    <Button        android:id="@+id/item4"        style="@style/MenuItemStyle"        android:background="@drawable/circle4"        android:visibility="gone" />    <Button        android:id="@+id/item5"        style="@style/MenuItemStyle"        android:background="@drawable/circle5"        android:visibility="gone" /></FrameLayout>

代码如下:

public class MainActivity extends Activity implements OnClickListener {    private static final String TAG = "MainActivity";    private Button mMenuButton;    private Button mItemButton1;    private Button mItemButton2;    private Button mItemButton3;    private Button mItemButton4;    private Button mItemButton5;    private boolean mIsMenuOpen = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    private void initView() {        mMenuButton = (Button) findViewById(R.id.menu);        mMenuButton.setOnClickListener(this);        mItemButton1 = (Button) findViewById(R.id.item1);        mItemButton1.setOnClickListener(this);        mItemButton2 = (Button) findViewById(R.id.item2);        mItemButton2.setOnClickListener(this);        mItemButton3 = (Button) findViewById(R.id.item3);        mItemButton3.setOnClickListener(this);        mItemButton4 = (Button) findViewById(R.id.item4);        mItemButton4.setOnClickListener(this);        mItemButton5 = (Button) findViewById(R.id.item5);        mItemButton5.setOnClickListener(this);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        mMenuButton.performClick();        getMenuInflater().inflate(R.menu.main, menu);        return false;    }    @Override    public void onClick(View v) {        if (v == mMenuButton) {            if (!mIsMenuOpen) {                mIsMenuOpen = true;                doAnimateOpen(mItemButton1, 0, 5, 300);                doAnimateOpen(mItemButton2, 1, 5, 300);                doAnimateOpen(mItemButton3, 2, 5, 300);                doAnimateOpen(mItemButton4, 3, 5, 300);                doAnimateOpen(mItemButton5, 4, 5, 300);            } else {                mIsMenuOpen = false;                doAnimateClose(mItemButton1, 0, 5, 300);                doAnimateClose(mItemButton2, 1, 5, 300);                doAnimateClose(mItemButton3, 2, 5, 300);                doAnimateClose(mItemButton4, 3, 5, 300);                doAnimateClose(mItemButton5, 4, 5, 300);            }        } else {            Toast.makeText(this, "你点击了" + v, Toast.LENGTH_SHORT).show();        }    }    /**     * 打开菜单的动画     * @param view 执行动画的view     * @param index view在动画序列中的顺序     * @param total 动画序列的个数     * @param radius 动画半径     */    private void doAnimateOpen(View view, int index, int total, int radius) {        if (view.getVisibility() != View.VISIBLE) {            view.setVisibility(View.VISIBLE);        }        double degree = Math.PI * index / ((total - 1) * 2);        int translationX = (int) (radius * Math.cos(degree));        int translationY = (int) (radius * Math.sin(degree));        Log.d(TAG, String.format("degree=%f, translationX=%d, translationY=%d",                degree, translationX, translationY));        AnimatorSet set = new AnimatorSet();        //包含平移、缩放和透明度动画        set.playTogether(                ObjectAnimator.ofFloat(view, "translationX", 0, translationX),                ObjectAnimator.ofFloat(view, "translationY", 0, translationY),                ObjectAnimator.ofFloat(view, "scaleX", 0f, 1f),                ObjectAnimator.ofFloat(view, "scaleY", 0f, 1f),                ObjectAnimator.ofFloat(view, "alpha", 0f, 1));        //动画周期为500ms        set.setDuration(1 * 500).start();    }    /**     * 关闭菜单的动画     * @param view 执行动画的view     * @param index view在动画序列中的顺序     * @param total 动画序列的个数     * @param radius 动画半径     */    private void doAnimateClose(final View view, int index, int total,            int radius) {        if (view.getVisibility() != View.VISIBLE) {            view.setVisibility(View.VISIBLE);        }        double degree = Math.PI * index / ((total - 1) * 2);        int translationX = (int) (radius * Math.cos(degree));        int translationY = (int) (radius * Math.sin(degree));        Log.d(TAG, String.format("degree=%f, translationX=%d, translationY=%d",                degree, translationX, translationY));        AnimatorSet set = new AnimatorSet();      //包含平移、缩放和透明度动画        set.playTogether(                ObjectAnimator.ofFloat(view, "translationX", translationX, 0),                ObjectAnimator.ofFloat(view, "translationY", translationY, 0),                ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f),                ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f),                ObjectAnimator.ofFloat(view, "alpha", 1f, 0f));        //为动画加上事件监听,当动画结束的时候,我们把当前view隐藏        set.addListener(new AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }            @Override            public void onAnimationEnd(Animator animator) {                view.setVisibility(View.GONE);            }            @Override            public void onAnimationCancel(Animator animator) {            }        });        set.setDuration(1 * 500).start();    }}
代码下载: http://download.csdn.net/detail/singwhatiwanna/6782865           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述
你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block var foo = 'bar'; 

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目 Value
电脑 $1600
手机 $12
导管 $1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列 第二列 第三列
第一列文本居中 第二列文本居右 第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPE ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n 1 ) ! n N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N 是通过欧拉积分

Γ ( z ) = 0 t z 1 e t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

gantt
        dateFormat  YYYY-MM-DD
        title Adding GANTT diagram functionality to mermaid
        section 现有任务
        已完成               :done,    des1, 2014-01-06,2014-01-08
        进行中               :active,  des2, 2014-01-09, 3d
        计划一               :         des3, after des2, 5d
        计划二               :         des4, after des3, 5d
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

猜你喜欢

转载自blog.csdn.net/qq_43661383/article/details/84026850