Android View 动画

View 动画框架

使用 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

通过布局动画(LayoutAnimation)给 ViewGroup 的子 View 指定入场动画。

也是一个 View 动画,作用于 ViewGroup,这样它的子元素出场时都会具有这种动画效果。

使用步骤

  1. 先写一个 tween 动画 xml
  2. 在写一个专门的 layoutAnimation xml 文件
  3. 最后给根节点的 viewGroup 设置上这个定义的 layoutAnimation

除了在 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添加初始动画的简单方法有几种:

  • 实现一个自定义的ItemAnimator
  • 在Adapter的onBindViewHolder()方法中添加动画
  • 采用LayoutAnimation;使用方式与上述ListView的差不多,代码在demo中。

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"
    />
    
    

    
    

    
    

    
    

    
    

    
    
    
    

    

为 Activity 自定义切换动画

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 动画

对于 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);

备注

欢迎关注微信公众号:非也缘也

你可能感兴趣的:(android,android)