Android 知识要点整理(12)----Animation(动画)

Posted znapast

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 知识要点整理(12)----Animation(动画)相关的知识,希望对你有一定的参考价值。

动画分类

android动画有3类:帧动画、视图动画、属性动画。帧动画和视图动画又统称为补间动画。Android 3.0(API LEVEL 11)开始支持属性动画

帧动画

帧动画是针对Drawable资源的动画。其本质是一系列Drawable资源的连续变化,其本质是AnimationDrawable对象。其使用方法如下:

定义AnimationDrawable

资源中用到了表示天气的三张图片

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="false">
    <item android:drawable="@mipmap/ic_sunny" android:duration="200" />
    <item android:drawable="@mipmap/ic_slight_drizzle" android:duration="200" />
    <item android:drawable="@mipmap/ic_haze" android:duration="200" />
</animation-list>

代码

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
        sampleIv.setBackgroundResource(R.drawable.wether_list);
        final AnimationDrawable animationDrawable = (AnimationDrawable)sampleIv.getBackground();
        sampleIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animationDrawable.start();
            }
        });

    }

效果图

点击图片之后就会连续变换不同的图片出来
这里写图片描述

视图动画

视图动画是对视图控件(View)应用动画,其本质是连续修改View的属性来展现变化。主要有Scale,Rotate,Translate,Alpha。使用方法如下:

定义动画资源

旋转动画

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
     android:fromDegrees="0"
            android:toDegrees="360"
            android:pivotX="50%"
            android:pivotY="50%"
 />

透明度动画

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0"
    android:toAlpha="1">
</alpha>

位移动画

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="-100%"
    android:toXDelta="0"
    android:fromYDelta="-20%"
    android:toYDelta="0">

</translate>

组合动画

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:fromAlpha="0.2"
        android:toAlpha="1">

    </alpha>
    <scale
        android:fromXScale="0%"
        android:fromYScale="0%"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="100%"
        android:toYScale="100%"/>
    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360"
        />
</set>

代码

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        final ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
        final Animation animation = AnimationUtils.loadAnimation(this,R.anim.roate360);
        animation.setDuration(1500);
        animation.setInterpolator(this,android.R.anim.linear_interpolator);
        animation.setRepeatCount(Animation.INFINITE);
        sampleIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sampleIv.startAnimation(animation);
            }
        });

    }

效果图

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

属性动画

接下来重点讲属性动画。
属性动画不仅仅针对视图(View),它几乎可以应用到任何对象。你可以定义属性动画来改变任意对象的属性,不管这个对象是否会在屏幕上呈现出来。属性动画的本质是在一定时间段内连续地改变对象的属性。

属性动画和视图动画的区别

  • 视图动画只能针对视图对象应用动画,而且视图动画只能针对视图的部分应用动画,例如可以缩放,旋转,但是不能对视图背景色应用动画等等。
  • 视图动画只会改变视图绘制的位置,而不会改变视图本身所在的位置。所以如果一个视图通过视图动画移动到了另一位置,你点击它的新位置并不会正确的响应点击事件,而必须在原来的初始位置点击才会有效果。
  • 属性动画则完全没有上边的限制,可以使用属性动画作用在任何对象的任何属性,不管它是视图控件还是非视图控件。并且,属性动画会真正的改变对象本身,事件都会在动画后的位置上生效。
  • 当然,使用视图动画的开销比属性动画要低,我们可用用很少的步骤和很少的代码去实现是视图动画效果。所以,如果视图动画可以达到目标,也没必要一定要用属性动画。

简单的例子

淡入淡出动画
showView.setAlpha(0f);
showView.setVisibility(View.VISIBLE);

showView.animate()
         .alpha(1f)
         .setDuration(300/*ms*/)
         .setListener(null);

hideView.animate()
        .alpha(0f)
        .setDuration(mShortAnimationDuration)
        .setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                hideView.setVisibility(View.GONE);
            }
         });
效果图

淡入淡出

翻转动画

下面展示如何在切换Fragmeng时应用翻转动画

java代码
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_card_flip);

        if (savedInstanceState == null) {
            // 如果没有实例,则将CardFrontFragment添加到Activity
            //否则表明之前已经添加Fragment了
            getFragmentManager()
                    .beginTransaction()
                    .add(R.id.container, new CardFrontFragment())
                    .commit();
        } else {
            mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
        }

        // 监控返回栈的变化,以便正确地显示操作图标
        getFragmentManager().addOnBackStackChangedListener(this);
    }

    @Override
    public void onBackStackChanged() {
        mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);

        // 当返回栈发生变化,更新菜单显示
        invalidateOptionsMenu();
    }

private void flipCard() {
        //如果返回栈中有实例,直接返回当前一个Fragment
        if (mShowingBack) {
            getFragmentManager().popBackStack();
            return;
        }

        //指示可以返回上一个Fragment
        mShowingBack = true;

        //添加CarBackFragment

        getFragmentManager()
                .beginTransaction()

                // 自定义Frameng切换时的动画
                //包括切换当当前Fragment和返回到上一个Fragment的动画
                //这样当按返回按钮时也会有动画效果
                .setCustomAnimations(
                        R.animator.card_flip_right_in/*enter*/, R.animator.card_flip_right_out/*exit*/,
                        R.animator.card_flip_left_in/*popEnter*/, R.animator.card_flip_left_out/*popExit*/)

                // 替换Fragment
                .replace(R.id.container, new CardBackFragment())

                // 将该事务添加到返回栈,这样才能响应返回按钮操作
                .addToBackStack(null)

                // 提交事务
                .commit();

        // 延迟更新菜单
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                invalidateOptionsMenu();
            }
        });
    }
动画资源

car_flip_right_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 在旋转动画之前,立刻将apha 设为0,注意duration=0 -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:duration="0" />

    <!-- 旋转动画 -->
    <objectAnimator
        android:valueFrom="180"
        android:valueTo="0"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="300" />

    <!-- 在旋转动画执行到二分之一的时候,立刻将alpha设为1,使之可见,注意 startOffset = 150. -->
    <objectAnimator
        android:valueFrom="0.0"
        android:valueTo="1.0"
        android:propertyName="alpha"
        android:startOffset="150"
        android:duration="1" />
</set>

card_flip_right_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 旋转 -->
    <objectAnimator
        android:valueFrom="0"
        android:valueTo="-180"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />

    <!-- 旋转一半的时候设置透明度为1,使之可见. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

card_flip_left_in.xmlcar_flip_right_in.xml差不多,只是rotationY动画的起止角度 valueFrom=”-180”,valueTo=”0”.
card_flip_left_out.xmlcar_flip_right_out.xml差不多,只是rotationY动画的起止角度 valueFrom=”0”,valueTo=”180”.

效果图

这里写图片描述

滑屏动画

下面展示有何在ViewPager切换Page的时候应用动画

java代码

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_slide);

        //实例化ViewPager和PagerAdapter对象
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
        mPager.setAdapter(mPagerAdapter);
        mPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                invalidateOptionsMenu();
            }
        });
    }

菜单操作

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {

            //...

            case R.id.action_zoom:
                //设置缩放动画,在切换page的时候会看到效果
                mPager.setPageTransformer(false,new ZoomPageTransformer());
                return true;
            case R.id.action_depth:
                mPager.setPageTransformer(false,new DepthPageTransformer());
                return true;
            case R.id.action_default:
                //恢复默认动画
                mPager.setPageTransformer(false,null);
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

DepthPageTransformer.java

public class DepthPageTransformer implements ViewPager.PageTransformer {
    @Override
    public void transformPage(View page, float position) {

        int pageWidth = page.getWidth();
        if(position <= -1){
            //当不在屏幕显示范围时,恢复所有属性
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
        }else if(position < 0){
            //屏幕左侧page
            page.setTranslationX(-position*pageWidth);
            page.setScaleX(position*0.3f+1f);
            page.setScaleY(position*0.3f+1f);
            page.setAlpha(1+position*0.8f);
        }else if(position < 1) {
            //屏幕右侧page
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
            page.setAlpha(1);

        }else{
            //当不在屏幕显示范围时,恢复所有属性
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
        }
    }
}

ZoomPageTransformer.java

public class ZoomPageTransformer implements ViewPager.PageTransformer {
    @Override
    public void transformPage(View page, float position) {

        if(position <= -1){
            //当不在屏幕显示范围时,恢复所有属性
            page.setScaleX(1);
            page.setScaleY(1);
            page.setTranslationX(0);
            page.setAlpha(1);
        }else if(position < 1){
            //在屏幕上显示的page
            float pageWidth = page.getWidth();
            float pageHeight = page.getHeight();
            float scaleFactor = Math.max(0.85f,1 -Math.abs(position));
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
            page.setAlpha(scaleFactor);

            float verticalMargin = pageHeight*(1-scaleFactor)/2;
            float horizonMargin = pageWidth*(1-scaleFactor)/2;
            if(position < 0){
                page.setTranslationX(horizonMargin-verticalMargin/2);
            }else {
                page.setTranslationX(-horizonMargin+verticalMargin/2);
            }
        }else{
            //当不在屏幕显示范围时,恢复所有属性
            page.setScaleX(1);
            page.setScaleY(1);
            page.setTranslationX(0);
            page.setAlpha(1);
        }

    }
}
效果图

这里写图片描述

缩放动画

java代码
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zoom);
        mImageRcv = (RecyclerView)findViewById(R.id.rcv_images);
        mAdapter = new ImageAdapter(this);
        mAdapter.setOnItemClickListener(new ImageAdapter.OnItemClickListener() {
            @Override
            public void onItemClicked(View view, int pos) {
                zoomImageFromThumb(view,mAdapter.getItemData(pos));
            }
        });
        mImageRcv.setAdapter(mAdapter);
        mImageRcv.setLayoutManager(new  GridLayoutManager(this,3,
                LinearLayoutManager.VERTICAL,false));

        mShortAnimationDuration = getResources()
        .getInteger(android.R.integer.config_shortAnimTime);
    }
    /**
     * 动画执行关键代码
     **/
    private void zoomImageFromThumb(final View thumbView, int imageResId) {
        // 取消上一个动画
        if (mCurrentAnimator != null) {
            mCurrentAnimator.cancel();
        }

        // 加载高清图片
        final ImageView expandedImageView = (ImageView) findViewById(R.id.expanded_image);
        expandedImageView.setImageResource(imageResId);

        // 计算尺寸,以便精准动画
        final Rect startBounds = new Rect();
        final Rect finalBounds = new Rect();
        final Point globalOffset = new Point();

        // 获取屏幕绝对坐标
        thumbView.getGlobalVisibleRect(startBounds);
        findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
        startBounds.offset(-globalOffset.x, -globalOffset.y);
        finalBounds.offset(-globalOffset.x, -globalOffset.y);

        //
        float startScale;
        if ((float) finalBounds.width() / finalBounds.height()
                > (float) startBounds.width() / startBounds.height()) {
            startScale = (float) startBounds.height() / finalBounds.height();
        } else {
            startScale = (float) startBounds.width() / finalBounds.width();

        }

        //隐藏缩略图并开始动画显示高清图
        thumbView.setAlpha(0f);
        expandedImageView.setVisibility(View.VISIBLE);

        // 设置动画的中心为坐标原点
        expandedImageView.setPivotX(0f);
        expandedImageView.setPivotY(0f);

        // 构造动画
        AnimatorSet set = new AnimatorSet();
        set
                .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
                        finalBounds.left))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
                        finalBounds.top))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
        set.setDuration(mShortAnimationDuration);
        set.setInterpolator(new DecelerateInterpolator());
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mCurrentAnimator = null;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                mCurrentAnimator = null;
            }
        });
        set.start();
        mCurrentAnimator = set;

        //再次点击还原,逆过程
        final float startScaleFinal = startScale;
        expandedImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mCurrentAnimator != null) {
                    mCurrentAnimator.cancel();
                }

                AnimatorSet set = new AnimatorSet();
                set
                        .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left))
                        .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
                set.setDuration(mShortAnimationDuration);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }
                });
                set.start();
                mCurrentAnimator = set;
            }
        });
    }
效果图

这里写图片描述


以上就是动画相关的知识。

以上是关于Android 知识要点整理(12)----Animation(动画)的主要内容,如果未能解决你的问题,请参考以下文章

Android 知识要点整理(13)----网络连接

Android知识要点整理----控制相机

Android 知识要点整理(13)----网络连接

Android知识要点整理----文件分享

Android知识要点整理(19)----Gradle 之构建变体

Android知识要点整理(19)----Gradle 之构建变体