Android转场动画总结篇(不基于Android5.0)

前言

前些天朋友发了一份居于Android5.0以下实现转场动画的代码,对动画挺感兴趣,所以就看了看效果的展示,果真跟5.0的转场动画一样,那么怎么实现的呢?有代码当然看代码了,那就看吧!

Ⅰ.简述

说明:效果就是点击当前列表页的某条目的图片,然后跳转到另个页面A,被点击的图片随着页面的跳转,缩放并移动到另一页面A的中心位置.

下面看下整体的代码实现吧!

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.MyRecyclerViewAdapterListener {
        private static final String TAG = MainActivity.class.getSimpleName();
        RecyclerView recyclerView;
        MyRecyclerViewAdapter myRecyclerViewAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            myRecyclerViewAdapter=new MyRecyclerViewAdapter();
            myRecyclerViewAdapter.setListener(this);
            recyclerView= (RecyclerView) findViewById(R.id.recyclerView);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
            recyclerView.setAdapter(myRecyclerViewAdapter);
        }

        @Override
        public void onItemClick(Rect srcRect, int imageId, String title) {         //rv条目点击事件的回调
            Intent intent = new Intent(this, SecondActivity.class);
            intent.putExtra("SRC_RECT", srcRect);
            intent.putExtra("IMAGE_ID",imageId);
            intent.putExtra("TITLE",title);
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);   //取消Activity跳转滑动的动画---->  Intent.FLAG_ACTIVITY_NO_ANIMATION
            startActivity(intent);
        }
    }

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyRecyclerViewHolder> {
        private static final int[] LOGOS = {R.drawable.logo0, R.drawable.logo1, R.drawable.logo2, R.drawable.logo3, R.drawable.logo4, R.drawable.logo5, R.drawable.logo6, R.drawable.logo7, R.drawable.logo8, R.drawable.logo9, R.drawable.logo10, R.drawable.logo11, R.drawable.logo12, R.drawable.logo13};
        MyRecyclerViewAdapterListener listener = null;

        @Override
        public MyRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
            return new MyRecyclerViewHolder(view, listener);
        }

        @Override
        public void onBindViewHolder(MyRecyclerViewHolder holder, int position) {
            holder.updateItem(LOGOS[position], "ITEM " + position);
        }

        @Override
        public int getItemCount() {
            return LOGOS.length;
        }

        public class MyRecyclerViewHolder extends RecyclerView.ViewHolder {
            MyRecyclerViewAdapterListener listener = null;
            int imageId;
            String title;
            ImageView itemIv;
            TextView itemTv;

            public MyRecyclerViewHolder(View itemView, MyRecyclerViewAdapterListener listener) {
                super(itemView);
                itemIv = (ImageView) itemView.findViewById(R.id.itemIv);
                itemTv = (TextView) itemView.findViewById(R.id.itemTv);
                this.listener = listener;
                this.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (MyRecyclerViewHolder.this.listener != null) {
                            int[] coords = new int[2];
                            itemIv.getLocationOnScreen(coords);                         //View在屏幕的左上角的x、y座标
                            Rect srcRect = new Rect(coords[0], coords[1], coords[0] + itemIv.getMeasuredWidth(), coords[1] + itemIv.getMeasuredWidth());

                            //上面将形状的大小用 rect标识出来,然后点击时带到下个页面
                            MyRecyclerViewHolder.this.listener.onItemClick(srcRect, imageId, title);
                        }
                    }
                });
            }
            public void updateItem(int imageId, String title) {
                this.imageId = imageId;
                this.title = title;
                itemIv.setImageResource(imageId);
                itemTv.setText(title);
            }
        }

        public void setListener(MyRecyclerViewAdapterListener listener) {
            this.listener = listener;
        }
        interface MyRecyclerViewAdapterListener {
            void onItemClick(Rect srcRect, int imageId, String title);
        }
    }

SecondActivity.java

public class SecondActivity extends AppCompatActivity {
        private static final String TAG = SecondActivity.class.getSimpleName();
        ImageView detailIv;
        View detailView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            detailIv = (ImageView) findViewById(R.id.detailIv);
            detailView=findViewById(R.id.detailView);
        }

        @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            super.onWindowFocusChanged(hasFocus);
            Rect srcRect = getIntent().getParcelableExtra("SRC_RECT");
            int[] coords = new int[2];
            detailIv.getLocationOnScreen(coords);                                //View在屏幕的左上角的x、y座标
            Rect targetRect = new Rect(coords[0], coords[1], coords[0] + detailIv.getMeasuredWidth(), coords[1] +detailIv.getMeasuredHeight());


            detailIv.setPivotX(0);                  //旋转或缩放的中心点X
            detailIv.setPivotY(0);                  //旋转或缩放的中心点Y

            //下面的设置移动和大小的补间动画是为了让detailIv还跟点击时候的位置和大小一样
            detailIv.setTranslationY(srcRect.top - targetRect.top);                 //用于设置detailIv左上角的Y值,设置的值是相对于原本左上角Y值的
            detailIv.setTranslationX(srcRect.left - targetRect.left);
            detailIv.setScaleX((float) srcRect.width() / targetRect.width());
            detailIv.setScaleY((float) srcRect.height() / targetRect.height());
            detailIv.setImageResource(getIntent().getIntExtra("IMAGE_ID",R.mipmap.ic_launcher));
            detailIv.setVisibility(View.VISIBLE);


            //移动到原有detailIv的位置,缩小到原有detailIv的大小,也就是还在中间位置,大小不变
            PropertyValuesHolder transY = PropertyValuesHolder.ofFloat("translationY", 0f);
            PropertyValuesHolder transX = PropertyValuesHolder.ofFloat("translationX", 0f);
            PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f);
            PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(detailIv, transY, transX, scaleX, scaleY).setDuration(900);
            animator.setInterpolator(new DecelerateInterpolator());
            animator.start();

            //让屏幕的背景渐变为原设置的背景色
            TransitionDrawable transitionDrawable= (TransitionDrawable) detailView.getBackground();
            transitionDrawable.startTransition(900);
        }

        @Override
        public void onBackPressed() {
            super.onBackPressed();
            overridePendingTransition(0,0);
        }
    }

Ⅱ.学习记录点

卡片布局

属性

<!--cardCornerRadius  卡片布局的边角半径-->
app:cardCornerRadius="10dp"         
<!--cardElevation   卡片布局的Z轴阴影-->
app:cardElevation="15dp">   

单一职责原则

下面的recyclerView三个需要重写的方法,是不是看着挺郁闷的,三个方法的方法体都是一两行代码而已。

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyRecyclerViewHolder> {   

        @Override
        public MyRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
            return new MyRecyclerViewHolder(view, listener);
        }

        @Override
        public void onBindViewHolder(MyRecyclerViewHolder holder, int position) {
            holder.updateItem(LOGOS[position], "ITEM " + position);
        }

         @Override
        public int getItemCount(){
            return LOGOS.length;
        }

    }

那么看看逻辑都跑到holder类里去处理了

public class MyRecyclerViewHolder extends RecyclerView.ViewHolder {
        MyRecyclerViewAdapterListener listener = null;
        int imageId;
        String title;
        ImageView itemIv;
        TextView itemTv;

        public MyRecyclerViewHolder(View itemView, MyRecyclerViewAdapterListener listener) {
            super(itemView);
            itemIv = (ImageView) itemView.findViewById(R.id.itemIv);
            itemTv = (TextView) itemView.findViewById(R.id.itemTv);
            this.listener = listener;
            this.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (MyRecyclerViewHolder.this.listener != null) {
                        int[] coords = new int[2];
                        itemIv.getLocationOnScreen(coords);
                        Rect srcRect = new Rect(coords[0], coords[1], coords[0] + itemIv.getMeasuredWidth(), coords[1] + itemIv.getMeasuredWidth());
                        MyRecyclerViewHolder.this.listener.onItemClick(srcRect, imageId, title);
                    }
                }
            });
        }
        public void updateItem(int imageId, String title) {
            this.imageId = imageId;
            this.title = title;
            itemIv.setImageResource(imageId);
            itemTv.setText(title);
        }
    }

接口回调

由于想对RecyclerView里的条目进行点击事件的监听处理,发现RecyclerView控件并没有提供setOnItemClickListener方法?? 凉拌了去…

//setOnClickListener明显没什么用,那么谷歌开发者为啥还提供了这个api,
      //点击进去源码发现setOnClickListener是从View类继承而来的,
      recyclerView.setOnClickListener(new View.OnClickListener() {        
                @Override
                public void onClick(View v) {

                }
      });

一不留神就跑去View类去了,还郁闷了半天setOnClickListener的用处,还不是继承惹的祸。那么既然要实现条目点击事件的监听,就来实现实现吧!

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyRecyclerViewHolder> {
        //将接口实现类传进来
        public void setListener(MyRecyclerViewAdapterListener listener) {
            this.listener = listener;
        }
        监听接口
        interface MyRecyclerViewAdapterListener {
            void onItemClick(Rect srcRect, int imageId, String title);
        }



        public class MyRecyclerViewHolder extends RecyclerView.ViewHolder {
            MyRecyclerViewAdapterListener listener = null;
            int imageId;
            String title;
            ImageView itemIv;
            TextView itemTv;

            public MyRecyclerViewHolder(View itemView, MyRecyclerViewAdapterListener listener) {
                super(itemView);
                itemIv = (ImageView) itemView.findViewById(R.id.itemIv);
                itemTv = (TextView) itemView.findViewById(R.id.itemTv);
                this.listener = listener;

                this.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                       if (MyRecyclerViewHolder.this.listener != null) {//记得判断是否为null
                            int[] coords = new int[2];
                            itemIv.getLocationOnScreen(coords);
                            Rect srcRect = new Rect(coords[0], coords[1], coords[0] + itemIv.getMeasuredWidth(), coords[1] + itemIv.getMeasuredWidth());
                            //将接口实现类进行注册
                            MyRecyclerViewHolder.this.listener.onItemClick(srcRect, imageId, title);
                        }
                    }
                });
            }

    }

好了,条目事件的监听通过接口回调的方式就解决了。

实现转场动画

关于Android5.0的转场动画,官方都给提供现成的api,现在问题是如何在5.0以下的系统实现转场动画,那么怎么实现呢?那就需要用到补间动画和属性动画咯,看实现的代码吧!多余的代码就不贴了。

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.MyRecyclerViewAdapterListener {

         @Override
        public void onItemClick(Rect srcRect, int imageId, String title) {          //rv条目点击事件的回调
            Intent intent = new Intent(this, SecondActivity.class);
            intent.putExtra("SRC_RECT", srcRect);   //当前被点击的图片,用于记录rect的大小位置
            intent.putExtra("IMAGE_ID",imageId);    //图片资源id
            intent.putExtra("TITLE",title);     
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);                 //取消Activity跳转滑动的动画---->  Intent.FLAG_ACTIVITY_NO_ANIMATION
            startActivity(intent);
        }
    }

点击触发回调的原点在上面MyRecyclerViewHolder内部类的OnClickListener里,上面已经对Rect进行了创建,可以看看。接着看点击之后跳转的页面的实现代码

public class SecondActivity extends AppCompatActivity {
        private static final String TAG = SecondActivity.class.getSimpleName();
        ImageView detailIv;
        View detailView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            detailIv = (ImageView) findViewById(R.id.detailIv);
            detailView=findViewById(R.id.detailView);
        }

        @Override
        public void onWindowFocusChanged(boolean hasFocus) {    
            super.onWindowFocusChanged(hasFocus);
            Rect srcRect = getIntent().getParcelableExtra("SRC_RECT");
            int[] coords = new int[2];
            detailIv.getLocationOnScreen(coords);     //coords存储View在屏幕的左上角的x、y座标
            Rect targetRect = new Rect(coords[0], coords[1], coords[0] + detailIv.getMeasuredWidth(), coords[1] +detailIv.getMeasuredHeight());

            detailIv.setPivotX(0);                  //旋转或缩放的中心点X
            detailIv.setPivotY(0);                  //旋转或缩放的中心点Y

            //下面的设置移动和大小的补间动画是为了让detailIv还跟点击时候的位置和大小一样
            detailIv.setTranslationY(srcRect.top - targetRect.top);                 //用于设置detailIv左上角的Y值,设置的值是相对于原本左上角Y值的
            detailIv.setTranslationX(srcRect.left - targetRect.left);
            detailIv.setScaleX((float) srcRect.width() / targetRect.width());
            detailIv.setScaleY((float) srcRect.height() / targetRect.height());
            detailIv.setImageResource(getIntent().getIntExtra("IMAGE_ID",R.mipmap.ic_launcher));
            detailIv.setVisibility(View.VISIBLE);


            //移动到原有detailIv的位置,缩小到原有detailIv的大小,也就是还在中间位置,大小不变
            PropertyValuesHolder transY = PropertyValuesHolder.ofFloat("translationY", 0f);
            PropertyValuesHolder transX = PropertyValuesHolder.ofFloat("translationX", 0f);
            PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f);
            PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(detailIv, transY, transX, scaleX, scaleY).setDuration(900);
            animator.setInterpolator(new DecelerateInterpolator());
            animator.start();

            //让屏幕的背景渐变为原设置的背景色
            TransitionDrawable transitionDrawable= (TransitionDrawable) detailView.getBackground();
            transitionDrawable.startTransition(900);
        }

        @Override
        public void onBackPressed() {
            super.onBackPressed();
            overridePendingTransition(0,0);
        }
    }

Ⅲ.个人总结

  1. 看他人的代码也是一种学习,那得耐得住
  2. 养成随时做笔记的好习惯,尼玛,去年敲的代码,今年都陌生了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章