美文网首页开发技巧Android知识Android开发
《Android编程权威指南》之属性动画篇

《Android编程权威指南》之属性动画篇

作者: 夜远曦白 | 来源:发表于2016-09-09 17:13 被阅读385次

    每次做项目写一些小Demo的时候,为了让程序跑的更加有趣,都会在设计的时候加上一些动画效果,提高用户体验,很有意思来着。

    Android基础动画分为:1. Tween Animation 变换动画 2. Frame Animation 帧动画 3. Layout Animation 布局动画 4. Property Animation 属性动画(相对复杂) 现在需要了解就是属性动画了,Demo来自于《Android编程权威指南》。

    Sunset项目这个demo是模拟一个落日景象。

    Demo截图

    res/values/colors.xml

    Demo截图

    res/drawable/sun.xml(在矩形视图上显示一个圆,模拟太阳)

    Demo截图

    res/layout/fragment_sunset.xml(日落场景布局)

    Demo截图 SingleFragmentActivity.java
    public abstract class SingleFragmentActivity extends AppCompatActivity {
        protected abstract Fragment createFragment();
        @LayoutRes
        protected int getLayoutRedId(){
            return R.layout.activity_fragment;
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(getLayoutRedId());
            FragmentManager fm = getSupportFragmentManager();
            Fragment fragment = fm.findFragmentById(R.id.fragment_container);
            if (fragment == null){
                fragment = createFragment();
                fm.beginTransaction().add(R.id.fragment_container, fragment).commit();
            }
        }
    }
    

    activity_fragment.xml

    Demo截图 SunsetActivity.java
    public class SunsetActivity extends SingleFragmentActivity {
        @Override
        protected Fragment createFragment() {
            return SunsetFragment.newInstance();
        }
    }
    

    SunsetFragment.java

    public class SunsetFragment extends Fragment {
        private View mSceneView;
        private View mSunView;
        private View mSkyView;
        private int mBlueSkyColor;
        private int mSunsetSkyColor;
        private int mNightSkyColor;
        public static SunsetFragment newInstance() {
            return new SunsetFragment();
        }
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_sunset, container, false);
            mSceneView = view;
            mSunView = view.findViewById(R.id.sun);
            mSkyView = view.findViewById(R.id.sky);
            Resources resources = getResources();
            mBlueSkyColor = resources.getColor(R.color.blue_sky);
            mSunsetSkyColor = resources.getColor(R.color.sunset_sky);
            mNightSkyColor = resources.getColor(R.color.night_sky);
            mSceneView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startAnimation();
                }
            });
            return view;
        }
        private void startAnimation() {
            float sunYStart = mSunView.getTop();  // 相对父视图的顶部位置
            float sunYEnd = mSkyView.getHeight(); // 此视图的高度
            ObjectAnimator heightAnimatior = ObjectAnimator.ofFloat(mSunView, "y", sunYStart, sunYEnd).setDuration(3000);
            heightAnimatior.setInterpolator(new AccelerateInterpolator());
            ObjectAnimator sunsetSkyAnimator = ObjectAnimator.ofInt(mSkyView, "backgroundColor", mBlueSkyColor, mSunsetSkyColor).setDuration(3000);
            sunsetSkyAnimator.setEvaluator(new ArgbEvaluator());
            ObjectAnimator nightSkyAnimator = ObjectAnimator.ofInt(mSkyView, "backgroundColor", mSunsetSkyColor, mBlueSkyColor).setDuration(3000);
            nightSkyAnimator.setEvaluator(new ArgbEvaluator());
            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.play(heightAnimatior).with(sunsetSkyAnimator).before(nightSkyAnimator);
            animatorSet.start();
    //        heightAnimatior.start();
    //        sunsetSkyAnimator.start();
        }
    }
    
    • 属性动画相关的类介绍:
      • ObjectAnimator: 动画的执行类
      • ValueAnimator: 动画的执行类
      • AnimatorSet:可以放一起执行的动画集,设置执行的先后顺序,时间等
      • AnimatorInflater: 加载属性动画的xml文件
      • TypeEvaluator: 类型估值,主要用于设置动画操作属性的值,能帮助ObjectAnimator对象精确地计算开始到结束间的递增值
      • TimeInterpolator: 时间插值,用于控制动画执行过程
      • PropertyValuesHolder: 属性存储器,为两个执行类提供更新多个属性的功能
      • Keyframe:为 PropertyValuesHolder提供多个关键帧的操作值
      • AnimatorUpdateListener:动画更新监听
      • AnimatorListener:动画执行监听,在动画开始、重复、结束、取消时进行回调
        总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。

    深入学习:其他动画 API

    Android属性动画 http://bbs.itheima.com/thread-172632-1-1.html (出处: 黑马程序员IT技术论坛)

    Hongyang 的两篇对属性动画完全解析
    http://blog.csdn.net/lmj623565791/article/details/38067475

    Android 4.4引入了新的视图转场框架。
    找到一个学习的博客 https://www.jianshu.com/p/98f2ec280945

    挑战练习

    1. 让日落可逆(点击屏幕,等太阳落下后,再次点击屏幕,让太阳升起来)这里我的实现方式将一些动画都定义为了类的成员变量,定义了两个boolean类型,一个用户判断是落日还是升日,一个用于判断用户是否第一次点击,这里由于要记录最开始太阳的位置,因为在onCreateView方法中得到太阳位置都是0,视图还没创建好,还有个判断是判别落日或者升日的动画是否正在执行,若是正在执行则点击屏幕无效
    public class SunsetFragment extends Fragment {
        private View mSceneView;
        private View mSunView;
        private View mSkyView;
        private int mBlueSkyColor;
        private int mSunsetSkyColor;
        private boolean isSunDown = true; // 是否落日
        private ObjectAnimator sunsetSkyAnimator;
        private ObjectAnimator nightSkyAnimator;
        private float sunYFirstStart;
        private float sunYFirstEnd;
        private boolean isFirstClick = true; // 是否第一次点击
        private ObjectAnimator downAnimatior;
        private AnimatorSet downAnimatorSet;
        private ObjectAnimator upAnimatior;
        private AnimatorSet upAnimatorSet;
        public static SunsetFragment newInstance() {
            return new SunsetFragment();
        }
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_sunset, container, false);
            mSceneView = view;
            mSunView = view.findViewById(R.id.sun);
            mSkyView = view.findViewById(R.id.sky);
            mBlueSkyColor = ContextCompat.getColor(getActivity(), R.color.blue_sky);
            mSunsetSkyColor = ContextCompat.getColor(getActivity(), R.color.sunset_sky);
            initSkyAnimation();
            mSceneView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (isFirstClick) {
                        sunYFirstStart = mSunView.getTop();
                        sunYFirstEnd = mSkyView.getHeight();
                        initUpDownAnimation();
                    }
                    isFirstClick = false;
                    if(!downAnimatorSet.isRunning() && !upAnimatorSet.isRunning()){
                        if (isSunDown) {
                            downAnimatorSet.start();
                        } else {
                            upAnimatorSet.start();
                        }
                        isSunDown = !isSunDown;
                    }
                }
            });
            return view;
        }
        // 初始化落日,升日动画
        private void initUpDownAnimation() {
            downAnimatior = ObjectAnimator.ofFloat(mSunView, "y", sunYFirstStart, sunYFirstEnd).setDuration(3000);
            downAnimatior.setInterpolator(new AccelerateInterpolator());
            downAnimatorSet = new AnimatorSet();
            downAnimatorSet.play(downAnimatior).with(sunsetSkyAnimator);
            upAnimatior = ObjectAnimator.ofFloat(mSunView, "y", sunYFirstEnd, sunYFirstStart).setDuration(3000);
            upAnimatior.setInterpolator(new AccelerateInterpolator());
            upAnimatorSet = new AnimatorSet();
            upAnimatorSet.play(upAnimatior).with(nightSkyAnimator);
        }
        // 初始化天空颜色两种动画
        private void initSkyAnimation() {
            sunsetSkyAnimator = ObjectAnimator.ofInt(mSkyView, "backgroundColor", mBlueSkyColor, mSunsetSkyColor).setDuration(3000);
            sunsetSkyAnimator.setEvaluator(new ArgbEvaluator());
            nightSkyAnimator = ObjectAnimator.ofInt(mSkyView, "backgroundColor", mSunsetSkyColor, mBlueSkyColor).setDuration(3000);
            nightSkyAnimator.setEvaluator(new ArgbEvaluator());
        }
    }
    
    1. 添加太阳动画特效(让它有规律地放大或是加一圈旋转的光线,海平面加上太阳倒影)
    2. 在日落过程中实现动画反转(在太阳慢慢下落时点击屏幕,让太阳无缝回升至原来所在位置,或者,在太阳落下进入夜晚时点击屏幕,让太阳重新升回天空)

    相关文章

      网友评论

      • 小默森:师父,能不能把你写的demo发给我研究一下,棒棒的
      • fab41426b988:泥巴子,棒棒哒
      • 空城新月:请问有Github源码地址吗?想法不错!
        空城新月: @Cherish08 可以总结一下,感觉代码是最好的老师
        夜远曦白: @空城新月 没有上传源码喔,这是对书中内容的总结,书里都有喔~😁

      本文标题:《Android编程权威指南》之属性动画篇

      本文链接:https://www.haomeiwen.com/subject/ibtfettx.html