动画
Android 动画分类(针对view控件的动画)
总的来说,Android动画可以分为两类:
最初的传统动画和Android3.0 之后出现的属性动画
传统动画又包括 帧动画(Frame Animation)和补间动画(Tweened Animation)
传统动画
帧动画
帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,
从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/a_0" android:duration="100" />
<item android:drawable="@drawable/a_1" android:duration="100" />
<item android:drawable="@drawable/a_2" android:duration="100" />
</animation-list>
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_animation);
ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
animationImg1.setImageResource(R.drawable.frame_anim1);
AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
animationDrawable1.start();
}
补间动画
补间动画又可以分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。
alpha_anim.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="0.0" />
scale.xml 动画实现
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0"/>
set 标签将多个动画组合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
</set>
在Activity中
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);
属性动画
属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
属性动画自定义
画最关键的三点就是 运动轨迹、小球半径及颜色的变化;我们就从这三个方面展开(用TypeEvaluator 确定运动轨迹)
public class PointSinEvaluator implements TypeEvaluator {
@Override public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = (float) (Math.sin(x * Math.PI / 180) * 100) + endPoint.getY() / 2;
Point point = new Point(x, y);
return point;
}
}
PointSinEvaluator 继承了TypeEvaluator类,并实现了他唯一的方法evaluate;这个方法有三个参数,第一个参数fraction 代表当前动画完成的百分比,这个值是如何变化的后面还会提到;第二个和第三个参数代表动画的初始值和结束值。
逻辑很简单,x的值随着fraction 不断变化,并最终达到结束值;y的值就是当前x值所对应的sin(x) 值,然后用x 和 y 产生一个新的点(Point对象)返回。
使用这个PointSinEvaluator 生成属性动画的实例
Point startP = new Point(RADIUS, RADIUS);
//初始值(起点)
Point endP = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
//结束值(终点)
final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
valueAnimator.setRepeatCount(-1);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue(); postInvalidate();
}
});
XML 属性动画
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
使用方式:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
set.setTarget(myObject);
set.start();
Android过渡动画(针对activity页面的动画)
Scene Transition(场景过渡动画)、Activity过渡动画、Shared Element Transition(共享元素过渡动画)
场景切换的共享元素源码已经上传到github
安卓5.0系统引入了共享元素,能做出非常炫酷的场景切换效果,这让人非常兴奋同时非常蛋疼,因为低版本没法使用啊,所以今天就跟大家分享一下自己写的一个库,其实只有2个文件而已,还是叫它工具比较合适吧......非常轻量级,简直是人畜无害,兼容安卓5.0以下的版本。
有ActivityA(简称A)和ActivityB(简称B),在A中启动B,再从B回退到A
·A启动B:
image·B回退到A:
image原理:
从A启动B时,首先需要构造一个EasyTransitionOptions对象,直接通过EasyTransitionOptions.makeTransitionOptions方法进行构造,传入的参数为ActivityA以及需要共享的元素View
image
首先调用了options.update方法,接着又获取了options的attrs并放到intent中,看看update方法:
image跟往常一样,构造一个Intent对象,然后调用EasyTransition.startActivity方法,传入了该Intent以及前面构造好的options,我们看看EasyTransition.startActivity做了什么
options使用传入的View填充了之前看到的那个ViewAttrs集合attrs,attrs存储了View的一些属性,分别为:
imageid用于获取B中的对应的View,startX和startY分别为View在A中的x、y坐标,这里通过View的getLocationOnScreen方法获取View在屏幕中的坐标,可以看到该方法的参数为int[] outLocation,以out开头的参数,意思即为执行方法后将填充该参数。width和height分别为View在A中的宽和高。
通过options获取Activity并调用真正的startActivity方法,然后再调用overridePendingTransition(0, 0)将系统的转场动画覆盖,0表示没有转场动画。
然后进入到B,我们在B的onCreate方法中,只调用了一个方法EasyTransition.enter
image
这个方法有很多个重载,最简单的只需要传入一个Activity参数即可。参数都很简单,分别为ActivityB,动画时间,动画的差值器以及动画监听。
通过Activity获取到Intent并拿到从A传入的ViewAttrs集合,接着执行了runEnterAnimation方法,到这里就要开始执行动画了,看看runEnterAnimation方法:
image
首先遍历attrs,通过id找到B中对应的View;然后在ViewTreeObserver.OnPreDrawListener中设置View的属性,其中scale属性设置为A中View的宽高与B中View的宽高的比,transition属性设置为A中View的坐标相对于B中View的坐标的偏移量,之所以使用屏幕坐标就是为了准确地算出坐标的偏移量,而不受状态栏等其他因素的影响。
从B回退到A,在回退的操作中,调用了EasyTransition.exit方法,
image
跟enter方法差不多,通过Activity获取到Intent,再拿到ViewAttrs集合,接着执行了runExitAnimation方法
image
遍历attrs,找到B中对应id的View,只不过这次动画是从View在B中的初始状态开始,变到View在A中的状态,属性还是那些属性,没有啥其他的。不一样的是,在执行动画后需要关闭B,所以调用了View.postDelayed方法,然后finish掉当前的Activity,依旧是覆盖一下系统的转场动画overridePendingTransition(0, 0)
场景过渡动画中有两个特别关键概念:Scene(场景),Transition(过渡)。
Scene(场景)
Scene代表一个场景。Scene保存了一个视图层级结构,包括它所有的views以及views的状态,
通常由getSceneForLayout (ViewGroup sceneRoot,int layoutId,Context context)获取Scene实例。
Transition(过渡)
Transition框架可以实现在starting scene和ending scene之间执行动画
我们不需要创建starting scene,因为starting scene通常由当前UI状态决定,我们只需要创建ending scene。
Android动画可以分为两类,最初的传统动画和Android3.0 之后出现的属性动画;
1.Touch feedback(触摸反馈)
2、Reveal effect(揭露效果)
3、Activity transitions(Activity转换效果)
4、Curved motion(曲线运动)
5、View state changes (视图状态改变)
6、Animate Vector Drawables(矢量动画)
LayoutAnimation、gridLayoutAnimation-给容器中的控件应用统一动画(针对viewGroup 容器的动画)
LayoutAnimation :普通viewGroup 添加统一的进入动画
gridLayoutAnimation: 针对 gridView 添加进入动画
LayoutAnimation 和 gridLayoutAnimation 在 API 1 中就有的函数,因为是在 API 1 中就引入了,
所以也只能使用 animtion 来做动画,而不能使用 animator。
一、LayoutAnimation
1. xml实现
第一步:在res/anim下新建单个item的slide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000" >
<translate
android:fromXDelta="-30%"
android:toXDelta="0" />
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
第二步:定义viewGroup的layout_animation
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/slide_in_left"
android:animationOrder="normal"
android:delay="1" />
LayoutAnimation详解:
delay:指每个 Item 的动画开始延时,取值是 android:animation 所指定动画时长的倍数,取值类型可以是 float 类型,也可以是百分数,默认是 0.5;
在 slide_in_left.xml 中android:duration="1000",即单次动画的时长是 1000 毫秒,而我们在这里的指定 android:delay=”1”,即一个 Item 的动画会在上一个 item 动画完成后延时单次动画时长的一倍时间开始,即延时 1000 毫秒后开始
animationOrder:指 viewGroup 中的控件动画开始顺序,取值有 normal(正序)、reverse(倒序)、random(随机)
animation:指定每个 item 入场所要应用的动画。仅能指定 res/aim 文件夹下的 animation 定义的动画,不可使用 animator 动画。
第三步:布局文件中的viewgroup引用
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/layout_animation"
/>
第四步:java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.listview);
arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, getData());
listView.setAdapter(arrayAdapter);
}
public List<String> getData() {
ArrayList<String> strings = new ArrayList<>();
for (int i = 0; i < 20; i++) {
strings.add("测试"+i);
}
return strings;
}
发现:
1.第二屏以及之后的数据并不会有动画
2.listview 中各个 item 从左至右滑入位置
3.动画仅在第一次创建时有用,后期加入的数据,将不会再有动画
android:layoutAnimation 只在 viewGroup 创建的时候,才会对其中的 item 添加动画。在创建成功以后,再向其中添加 item 将不会再有动画。
2. LayoutAnimation 的代码实现—LayoutAnimationController
Animation loadAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_in_left);
LayoutAnimationController layoutAnimationController=new LayoutAnimationController(loadAnimation);
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
layoutAnimationController.setDelay(1);
listView.setLayoutAnimation(layoutAnimationController);
listView.startLayoutAnimation();
二、GridLayoutAnimation
1. xml实现
建立item的动画,和LayoutAnimation一样的slide_in_left.xml
建立gridlayout_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:rowDelay="75%"
android:columnDelay="60%"
android:directionPriority="row"
android:direction="top_to_bottom|right_to_left"
android:animation="@android:anim/slide_in_left"
/>
rowDelay:每一行动画开始的延迟。与 LayoutAnimation 一样
columnDelay:每一列动画开始的延迟。取值类型及意义与 rowDelay 相同。
directionPriority:方向优先级。取值为 row,collumn,none,意义分别为:行优先,列优先,和无优先级(同时进行)
direction:gridview 动画方向。
left_to_right:列,从左向右开始动画
right_to_left :列,从右向左开始动画
top_to_bottom:行,从上向下开始动画
bottom_to_top:行,从下向上开始动画
这四个值之间可以通过“|”连接,从而可以取多个值。很显然 left_to_right 和 right_to_left 是互斥的,top_to_bottom 和 bottom_to_top 是互斥的。如果不指定 direction 字段,默认值为 left_to_right | top_to_bottom;即从上往下,从左往右。
animation: gridview 内部元素所使用的动画。
xml中引用
<GridView
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:gravity="center"
android:horizontalSpacing="10dp"
android:layoutAnimation="@anim/gridlayout_animation"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp"
/>
最后一步
arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, getData());
gridView.setAdapter(arrayAdapter);
网友评论