使用 View 动画框架可以在 View 上执行补间动画。
补间动画是指,只要指定动画的开始与结束的“关键帧”,而动画变化的“中间帧”由系统计算并补齐。
动画并没有改变 View 的实际位置,仅是改变了 View 的显示位置。
FILE LOCATION:
res/anim/filename.xml
The filename will be used as the resource ID.
COMPILED RESOURCE DATATYPE:
Resource pointer to an Animation.
RESOURCE REFERENCE:
In Java: R.anim.filename
In XML: @[package:]anim/filename
文件位置:
res /anim/ filename.xml
文件名将用作资源ID。
编制资源数据类型:
指向动画的资源指针。
资源引用:
在Java: R.anim.filename
在XML: @包:anim/文件名
// XML使用
// res /anim/ anim_layout.xml
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/anim_file"
android:animationOrder="normal"
android:delay="0.5">
layoutAnimation>
// res /layout/ activity_main.xml
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/anim_layout"
android:divider="#f1f1f1"
android:dividerHeight="1dp">
ListView>
语法:
<--透明度动画-->
<--缩放动画-->
<--平移动画-->
<--旋转动画-->
<set>
...
set>
set>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Animation animation;
private TextView tvAlpha,tvScale,tvTranslate,tvRotate;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
// animation = AnimationUtils.loadAnimation(this,R.anim.anim_alpha);
// 因为有动画链的原因,假定有一个移动的动画紧跟一个淡出的动画,
// 如果不把移动的动画的setFillAfter置为true,那么移动动画结束后,View会回到原来的位置淡出,
// 就像重置了一样,动画执行完,回到初始样式。
// 如果setFillAfter置为true, 就会在移动动画结束的位置淡出
// 也就是动画执行完,会保持动画执行后的样式。
// animation.setFillAfter(true);
// iv.startAnimation(animation);
}
private void initView() {
iv=findViewById(R.id.iv_main_anim);
tvAlpha=findViewById(R.id.tv_main_alpha);
tvScale=findViewById(R.id.tv_main_scale);
tvTranslate=findViewById(R.id.tv_main_translate);
tvRotate=findViewById(R.id.tv_main_rotate);
tvAlpha.setOnClickListener(this);
tvScale.setOnClickListener(this);
tvTranslate.setOnClickListener(this);
tvRotate.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.tv_main_alpha:
animation = AnimationUtils.loadAnimation(this,R.anim.anim_alpha);
iv.startAnimation(animation);
break;
case R.id.tv_main_scale:
animation = AnimationUtils.loadAnimation(this,R.anim.anim_scale);
iv.startAnimation(animation);
break;
case R.id.tv_main_translate:
animation = AnimationUtils.loadAnimation(this,R.anim.anim_translate);
iv.startAnimation(animation);
break;
case R.id.tv_main_rotate:
animation = AnimationUtils.loadAnimation(this,R.anim.anim_ratate);
iv.startAnimation(animation);
break;
default:
break;
}
}
}
/**
* 透明度动画
**/
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="2000" />
set>
/**
* 缩放动画
**/
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="0.0"
android:toYScale="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"/>
set>
/**
* 平移动画
**/
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="20"
android:fromYDelta="20"
android:toXDelta="100"
android:toYDelta="100"
android:duration="2000" />
set>
/**
* 旋转动画
**/
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="-360"
android:pivotY="50%"
android:pivotX="50%"
android:duration="2000" />
set>
通过布局动画(LayoutAnimation)给 ViewGroup 的子 View 指定入场动画。
也是一个 View 动画,作用于 ViewGroup,这样它的子元素出场时都会具有这种动画效果。
使用步骤:
除了在 XML 中指定 LayoutAnimation 外,还可通过 LayoutAnimationController 来实现。
ListView
/**
* res/anim/zoom_in.xml
**/
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="500" />
<scale
android:fromXScale="0.1"
android:fromYScale="0.1"
android:toYScale="1.0"
android:toXScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="500" />
set>
1.通过xml的方式
/**
* activity_main.xml
**/
<ListView
android:id="@+id/lv_main"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/anim_layout"
android:divider="#f1f1f1"
android:dividerHeight="1dp"
android:scrollbars="none">
ListView>
/**
* res/anim/anim_layout.xml
**/
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/zoom_in"
android:animationOrder="random"
android:delay="0.5">
layoutAnimation>
2.通过动态代码的方式
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tvListview;
private ListView lv;
private String datas[]={ "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday" };
private ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
adapter=new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,datas);
lv.setAdapter(adapter);
LayoutAnimationController lac = new LayoutAnimationController(AnimationUtils.loadAnimation(this,R.anim.zoom_in));
lac.setDelay(0.5f);
lac.setOrder(LayoutAnimationController.ORDER_RANDOM);
lv.setLayoutAnimation(lac);
lv.setLayoutAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
Toast.makeText(MainActivity.this,"end",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
private void initView() {
tvListview=findViewById(R.id.tv_main_listview);
lv=findViewById(R.id.lv_main);
tvListview.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.tv_main_listview:
lv.startLayoutAnimation();
break;
default:
break;
}
}
}
RecyclerView
对于给RecyclerView添加初始动画的简单方法有几种:
GridView
对于GridView,为了展示效果更好,可以使用GridLayoutAnimation来实现。
主要就是动画文件的不同,其它类似。代码在demo中。
<gridLayoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_anim_gridview"
android:animationOrder="normal"
android:startOffset="700"
android:columnDelay="15%"
android:rowDelay="15%"
android:direction="top_to_bottom|left_to_right"
/>
1.通过调用 Activity 类的 overridePendingTransition(int enterAnim, int exitAnim) 方法可以实现自定义Activity 的切换动画,注意这个方法必须在 startActivity 和 finish 调用之后被调用,否者没有效果。
Fragment(API 11 引入) 可以通过 FragmentTransaction 中的 setCustomAnimations() 来添加切换动画(View 动画)。
注意,要使用 support-v4 兼容包。
public class CustomSwitchingActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.custom_in,0);
setContentView(R.layout.activity_custom_switching);
}
public void back(View view){
finish();
overridePendingTransition(0, R.anim.custom_out);
}
@Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(0, R.anim.custom_out);
}
}
2.使用style的方式定义Activity的切换动画
貌似问题很多
对于 View 动画,建议采用 XML 来定义动画,因为 XML 格式的动画可读性更好。
需要继承 Animation 这个抽象类,并重写 initialize() 和 applyTransformation()。
public class Rotate3dAnimation extends Animation{
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthz;
private final boolean mReverse;
// 简化矩阵变换
private Camera mCamera;
public Rotate3dAnimation(float mFromDegrees, float mToDegrees, float mCenterX, float mCenterY, float mDepthz, boolean mReverse) {
this.mFromDegrees = mFromDegrees;
this.mToDegrees = mToDegrees;
this.mCenterX = mCenterX;
this.mCenterY = mCenterY;
this.mDepthz = mDepthz;
this.mReverse = mReverse;
}
/**
* 做一些初始化工作
*/
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
/**
* 进行相应的矩阵变换
*/
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees+((mToDegrees-fromDegrees)*interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
if (mReverse){
camera.translate(0.0f,0.0f,mDepthz*interpolatedTime);
}else {
camera.translate(0.0f,0.0f,mDepthz*(1.0f-interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX,-centerY);
matrix.postTranslate(centerX,centerY);
}
}
Rotate3dAnimation rotate3dAnimation = new Rotate3dAnimation(0,360,100,100,100,true);
rotate3dAnimation.setDuration(2000);
// 重复次数
rotate3dAnimation.setRepeatCount(1);
// 动画结束,停留在原地
rotate3dAnimation.setFillAfter(true);
rotate3dAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.e(TAG,"onAnimationStart");
}
@Override
public void onAnimationEnd(Animation animation) {
Log.e(TAG,"onAnimationEnd");
}
@Override
public void onAnimationRepeat(Animation animation) {
Log.e(TAG,"onAnimationRepeat");
}
});
tv.startAnimation(rotate3dAnimation);
欢迎关注微信公众号:非也缘也