逐帧动画Frame Animation :其实也可以规划到视图动画的类别,用来一个一个的显示drawable的resources。
视图动画Tween Animation:也叫补间动画,可以在一个视图容器内执行一系列简单变换(位置,大小,旋转,透明度)实现的原理是每次绘制视图时view所在的viewgroup中的drawchild函数获取该viewanimation的transformation值。然后调用canvas.concat()通过矩阵运算完成动画zhen动画帧。如果动画没有完成,就继续调用invalidate函数启动下次绘制来驱动动画,从而完成整个动画的绘制。它有一个缺点,不具备交互性,当某个元素发生视图动画后,其响应事件的位置还依然在动画前的地方,(例如,将一个按钮向右平移10个单位,但是它的点击事件还是在平移之前的那个位置,而不是平移后显示的位置)所以视图动画只能做普通的动画效果,避免交互的发生。但是它的效率高,使用方便。
属性动画Propety Animation:只对android3.0以上的版本才有效,这种动画可以设置给任何object,包括那些还没有渲染到屏幕上的对象,这种动画是可以扩展的,可以让自定义任何类型和属性的动画。
视图动画示例:
public class AnimationActivity
extends AppCompatActivity
implements View.OnClickListener {
private ImageView
ainmationImg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_animation)
;
initView()
;
}
private void initView() {
ainmationImg = ((ImageView) findViewById(R.id.
animationImg))
;
findViewById(R.id.
touming).setOnClickListener(
this)
;
findViewById(R.id.
xuanzhuan).setOnClickListener(
this)
;
findViewById(R.id.
weiyi).setOnClickListener(
this)
;
findViewById(R.id.
suofang).setOnClickListener(
this)
;
findViewById(R.id.
jihe).setOnClickListener(
this)
;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.
touming:
toumingAnimation()
;
break;
case R.id.
xuanzhuan:
xuanzhuanAnimation()
;
break;
case R.id.
weiyi:
weiyiAnimation()
;
break;
case R.id.
suofang:
soufangAnimation()
;
break;
case R.id.
jihe:
jiheAnimation()
;
break;
}
}
/**
* 透明动画
*/
private void toumingAnimation() {
AlphaAnimation alphaAnimation =
new AlphaAnimation(
0, 1)
;
alphaAnimation.setDuration(
1000)
;
ainmationImg.startAnimation(alphaAnimation)
;
}
/**
* 集合动画,添加多种动画效果
*/
private void jiheAnimation() {
AnimationSet as =
new AnimationSet(
true)
;
as.setDuration(
1000)
;
AlphaAnimation alphaAnimation =
new AlphaAnimation(
0, 1)
;
alphaAnimation.setDuration(
1000)
;
as.addAnimation(alphaAnimation)
;
ScaleAnimation anmation =
new ScaleAnimation(
0, 2, 0, 2)
;
anmation.setDuration(
1000)
;
as.addAnimation(anmation)
;
RotateAnimation animation =
new RotateAnimation(
0, 360, 100, 100)
;
animation.setDuration(
1000)
;
as.addAnimation(animation)
;
ainmationImg.startAnimation(as)
;
}
/**
* 缩放动画
*/
private void soufangAnimation() {
ScaleAnimation anmation =
new ScaleAnimation(
0, 2, 0, 2)
;
anmation.setDuration(
1000)
;
ainmationImg.startAnimation(anmation)
;
}
/**
* 位移动画
*/
private void weiyiAnimation() {
TranslateAnimation animation =
new TranslateAnimation(
0, 200, 0, 300)
;
animation.setDuration(
1000)
;
ainmationImg.startAnimation(animation)
;
}
/**
* 旋转动画
*/
private void xuanzhuanAnimation() {
// 参数:1旋转的起始角度和旋转中心点的坐标
RotateAnimation animation =
new RotateAnimation(
0, 360, 100, 100)
;
animation.setDuration(
1000)
;
ainmationImg.startAnimation(animation)
;
}
private void animationListener(Animation animation) {
//动画的监听
animation.setAnimationListener(
new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
})
;
}
}
xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_animation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.lvqueen.qunyinzhuan.day07.AnimationActivity">
<ImageView
android:id="@+id/animationImg"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:src="@mipmap/shoukuan" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<Button
android:id="@+id/touming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="透明" />
<Button
android:id="@+id/xuanzhuan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="旋转" />
<Button
android:id="@+id/weiyi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="位移" />
<Button
android:id="@+id/suofang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="缩放" />
</LinearLayout>
<Button
android:id="@+id/jihe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="集合" />
</LinearLayout>
</RelativeLayout>
属性动画示例
public class AnimatorActivity
extends AppCompatActivity {
private ImageView
imgView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_animator)
;
initView()
;
}
private void initView() {
imgView = ((ImageView) findViewById(R.id.
animatorImg))
;
// pingyiAnimator();
// jiheAnimator();
// orderManyAnimator();
useXmlAnimator()
;
}
/**
* 在使用ObjectAnimator的时候,操纵的属性必须具有get和set方法,不然ObjectAnimator就无效。
* 如果没有,可以通过自定义一个属性类或者包装类,来间接的给这个属性增加get,set方法,活着通过ValueAnimator
* 可以直接使用属性动画的属性值
* translationX,translationY:为一种增量来控制view对象从它的布局容器的左上角坐标偏移的位置。
* rotation,rotationX,rotationY:控制view对象围绕它的支点进行2D,3D旋转
* scaleX,scaleY:控制view围绕它的支点进行2D缩放。
* pivotX,pivotY:控制view围绕支点进行旋转和缩放变换处理。默认情况下,支点位置就是view对象的中心点
* x,y:描述了view对象在他的容器中的最终位置,它是最初的左上角坐标和translationX,translationY值的累计和
* alpha:表示view的透明度,默认值为1不透明,0为完全透明。
*/
private void pingyiAnimator() {
// 参数1:要操纵的view。参数2:操纵的属性。参数三:可变的数组参数
ObjectAnimator animator = ObjectAnimator.
ofFloat(
imgView, "translationX", 300)
;
// ObjectAnimator animator = ObjectAnimator.ofFloat(imgView, "translationX", 300);
animator.setDuration(
1000)
;
animator.start()
;
}
/**
* 添加多种动效PropertyValuesHolder
*/
private void jiheAnimator() {
PropertyValuesHolder translationX = PropertyValuesHolder.
ofFloat(
"translationX", 300f)
;
PropertyValuesHolder translationY = PropertyValuesHolder.
ofFloat(
"translationY", 300f)
;
PropertyValuesHolder scaleX = PropertyValuesHolder.
ofFloat(
"scaleX", 1f, 0, 1f)
;
ObjectAnimator.
ofPropertyValuesHolder(
imgView, translationX
, scaleX
, translationY).setDuration(
1000).start()
;
}
/**
* 顺序添加多种动效
*/
private void orderManyAnimator() {
ObjectAnimator animator = ObjectAnimator.
ofFloat(
imgView, "translationX", 100)
;
ObjectAnimator animator1 = ObjectAnimator.
ofFloat(
imgView, "translationY", 100)
;
AnimatorSet animatorSet =
new AnimatorSet()
;
animatorSet.setDuration(
1000)
;
animatorSet.playTogether(animator
, animator1)
;
animatorSet.start()
;
}
private void useXmlAnimator(){
// Animator animator = AnimatorInflater.loadAnimator(this, R.anim.animator_test);
// animator.setTarget(imgView);
// animator.start();
}
// view 的animate方法添加动画
private void animateUse(){
imgView.animate().alpha(
0).y(
300).setDuration(
1000).withStartAction(
new Runnable() {
@Override
public void run() {
}
}).withEndAction(
new Runnable() {
@Override
public void run() {
runOnUiThread(
new Runnable() {
@Override
public void run() {
}
})
;
}
}).start()
;
}
private void valueAnimatorFactory() {
ValueAnimator valueAnimator = ValueAnimator.
ofFloat(
0, 100)
;
valueAnimator.setTarget(
imgView)
;
valueAnimator.setDuration(
1000).start()
;
valueAnimator.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) valueAnimator.getAnimatedValue()
;
// TODO use the value
// 在这里监听数值的变换,从而完成动画的变换。
}
})
;
}
/**
* 动效的监听
*
* @param animator
*/
private void animationListener(ObjectAnimator animator) {
animator.addListener(
new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
})
;
// 通常情况下我们只关心动画结束时,所以还提供了一个,来选择必要的事件进行监听
animator.addListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation)
;
}
})
;
}
}
示例三:布局动画,给子视图出现添加动画
public class BujuActivity
extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_buju)
;
addAnimation()
;
}
/**
* 给子视图出现添加动画
* 参数1:需要作用的动画,参数2:子view现实的delay时间
* LayoutAnimationController.ORDER_NORMAL:顺序依次出现
* LayoutAnimationController.ORDER_RANDOM :随机出现
* LayoutAnimationController.ORDER_REVERSE:倒序出现
*/
private void addAnimation() {
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.
activity_buju)
;
ScaleAnimation scaleAnimation =
new ScaleAnimation(
0, 1, 0, 1)
;
scaleAnimation.setDuration(
1000)
;
LayoutAnimationController controller =
new LayoutAnimationController(scaleAnimation
, 0.5f)
;
controller.setOrder(LayoutAnimationController.
ORDER_REVERSE)
;
linearLayout.setLayoutAnimation(controller)
;
}
}
插值器Interpolators
插值器可以定义动画变换速率,类似于物理中的加速度,主要控制目标变量的变化值进行对应的变化。同样的,一个动画变换起始值,在不同的插值器作用下,每个单位时间内所达到的变化值也是不一样的。
自定义动画
示例1:模拟电视机关闭的图像
public class CustomTv
extends Animation{
// 缩放的中心点
private int mCenterWidth;
private int mCenterHeight;
private Camera
mcamera =
new Camera()
;
private float mRotateY =
0.0f;
@Override
public void initialize(
int width
, int height
, int parentWidth
, int parentHeight) {
super.initialize(width
, height
, parentWidth
, parentHeight)
;
// 设置默认时常
setDuration(
1000)
;
// 动画结束后保留状态
setFillAfter(
true)
;
// 设置默认插值器
setInterpolator(
new AccelerateInterpolator())
;
mCenterWidth = width/
2;
mCenterHeight = height/
2;
}
public void setRotateY(
float rorateY){
mRotateY = rorateY
;
}
@Override
protected void applyTransformation(
float interpolatedTime
, Transformation t) {
// 获得矩阵对象
final Matrix matrix = t.getMatrix()
;
// 通过对矩阵的各种操作来实现动效
matrix.preScale(
1,1-interpolatedTime
,mCenterWidth,mCenterHeight)
;
}
}
使用:
CustomTv customTv =
new CustomTv()
;
customTv.setRotateY(
30)
;
imgView.startAnimation(customTv)
;
android5.x SVG(可伸缩矢量图形)矢量动画机制
可伸缩矢量图形(scalable vector graphics)
定义用于网络的基于矢量的图形
使用XML格式定义图形
图像在放大或者改变尺寸的情况下其图形质量不会有所损失
万维网联盟的标准
与诸如dom 和xsl之类的问c标准是一个整体
与传统bitmap相比,svg是一个绘图标准,它放大不会失真,而bitmap需要为不同分辨率设计多套图标,矢量图不需要。
它是通过<path>标签创建svg,这些指令一时没看懂,没信心看下去了。
动画特效
一个点击一个按钮,发散出四个按钮的动画,类似于菜单demo
public class SupriseAnimationActivity
extends AppCompatActivity
implements View.OnClickListener {
private int[]
mRes = {R.id.
imageView_a, R.id.
imageView_b, R.id.
imageView_c, R.id.
imageView_d, R.id.
imageView_e,}
;
private List<ImageView>
imageViews =
new ArrayList<>()
;
private boolean mFlag =
true;
private ImageView
imgview;
private TextView
text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_suprise_animation)
;
initView()
;
}
private void initView() {
text = ((TextView) findViewById(R.id.
tv_texts))
;
for (
int i =
0; i <
mRes.
length; i++) {
imgview = ((ImageView) findViewById(
mRes[i]))
;
imgview.setOnClickListener(
this)
;
imageViews.add(
imgview)
;
}
}
private void startAnim() {
ObjectAnimator animator = ObjectAnimator.
ofFloat(
imageViews.get(
0)
, "alpha", 0.5F, 1F)
;
ObjectAnimator animator1 = ObjectAnimator.
ofFloat(
imageViews.get(
1)
, "translationY", -
100F)
;
ObjectAnimator animator2 = ObjectAnimator.
ofFloat(
imageViews.get(
2)
, "translationX", -
100F)
;
ObjectAnimator animator3 = ObjectAnimator.
ofFloat(
imageViews.get(
3)
, "translationY", 100F)
;
ObjectAnimator animator4 = ObjectAnimator.
ofFloat(
imageViews.get(
4)
, "translationX", 100F)
;
AnimatorSet animatorSet =
new AnimatorSet()
;
animatorSet.setDuration(
1000)
;
animatorSet.setInterpolator(
new BounceInterpolator())
;
animatorSet.playTogether(animator
,animator1
,animator2
,animator3
,animator4)
;
animatorSet.start()
;
mFlag=
false;
}
private void stopAnim() {
ObjectAnimator animator = ObjectAnimator.
ofFloat(
imageViews.get(
0)
, "alpha", 0.5F, 1F)
;
ObjectAnimator animator1 = ObjectAnimator.
ofFloat(
imageViews.get(
1)
, "translationY", 100F, 0)
;
ObjectAnimator animator2 = ObjectAnimator.
ofFloat(
imageViews.get(
2)
, "translationX", 100F, 0)
;
ObjectAnimator animator3 = ObjectAnimator.
ofFloat(
imageViews.get(
3)
, "translationY", -
100F, 0)
;
ObjectAnimator animator4 = ObjectAnimator.
ofFloat(
imageViews.get(
4)
, "translationX", -
100F, 0)
;
AnimatorSet animatorSet =
new AnimatorSet()
;
animatorSet.setDuration(
1000)
;
animatorSet.setInterpolator(
new BounceInterpolator())
;
animatorSet.playTogether(animator
,animator1
,animator2
,animator3
,animator4)
;
animatorSet.start()
;
mFlag=
true;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.
imageView_a:
if (
mFlag) {
startAnim()
;
}
else {
stopAnim()
;
}
break;
default:
Toast.
makeText(getApplicationContext()
, view.getId() +
"", Toast.
LENGTH_LONG).show()
;
tvTimer(
text)
;
break;
}
}
private void tvTimer(
final TextView view){
final ValueAnimator animator = ValueAnimator.
ofInt(
0,100)
;
animator.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
view.setText(
"$"+(Integer)
animator.getAnimatedValue())
;
}
})
;
animator.setDuration(
3000)
;
animator.start()
;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_suprise_animation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.lvqueen.qunyinzhuan.day08.SupriseAnimationActivity">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_b"
android:src="@mipmap/b"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_c"
android:src="@mipmap/c"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_d"
android:src="@mipmap/d"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_e"
android:src="@mipmap/e"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView_a"
android:src="@mipmap/a"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<TextView
android:id="@+id/tv_texts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test"/>
</RelativeLayout>