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. 養成隨時做筆記的好習慣,尼瑪,去年敲的代碼,今年都陌生了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章