利用Transition,實現朋友圈點擊圖片全屏瀏覽效果

本文主要是介紹 Android 5.0 之後的 Activity 過渡動畫 Transition。如果是整個頁面的動畫,實際大部分都可以用 overridePendingTransition 實現了。這裏主要還是介紹當第二個界面的出現方式與第一個界面有一定的關聯性的時候,特別是有共享同一元素的時候,需要的連貫的過渡動畫。

先看效果圖:

具體實現:

1,首先當我們用到 Transition時,需要 Activity OnCreate之前設置:

getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);

public class ListActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        super.onCreate(savedInstanceState);
        // ....省略代碼
    }
}

2,啓動第二個頁面 PageActivity 的時候,帶上 OptionsBundle:

public class ListActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        super.onCreate(savedInstanceState);
        
        // ...省略代碼

        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                PageActivity.mCurPosition = position;
                Intent intent = new Intent(ListActivity.this, PageActivity.class);
                intent.putExtra("data", mData);
                intent.putExtra("position", position);
                ActivityCompat.startActivity(ListActivity.this, intent, ActivityOptionsCompat.makeSceneTransitionAnimation(ListActivity.this, view, "share").toBundle());
            }
        });

        // ...省略代碼
    }
}

ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)

參數說明:

sharedElement: 共享哪個View;

sharedElementName: 共享元素的名稱;這個是自己定義的;保證第一個頁面 和第二個頁面 的共享元素名稱一樣就行;

3,第二個頁面需要延遲開始動畫,因爲是 ViewPage 結構,需要等 View 開始繪製,纔可以開始動畫:

public class PageActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        super.onCreate(savedInstanceState);
       
        // ...省略代碼

        // 延遲動畫
        ActivityCompat.postponeEnterTransition(this);
    }

    private void scheduleStartPostponedTransition(final View sharedElement) {
        sharedElement.getViewTreeObserver().addOnPreDrawListener(
                new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        // 啓動動畫
                       sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
                        ActivityCompat.startPostponedEnterTransition(PageActivity.this);
                        return true;
                    }
                });
    }

    public void goBack() {
        // 返回的時候,也過渡動畫
        ActivityCompat.finishAfterTransition(this);
    }

    class MyPageAdapter extends PagerAdapter {
        // ...省略代碼

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            // ...省略代碼

            if (mCurPosition == position) {
                // 設置共享元素名稱
                ViewCompat.setTransitionName(img, "share");
                scheduleStartPostponedTransition(img);
            }

            // ...省略代碼

            img.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 返回的時候,重新設置 View 共享元素名稱
                    ViewCompat.setTransitionName(v, "share");
                    goBack();
                }
            });
            return layout;
        }

        // ...省略代碼
    }
}

4,因爲 共享元素是 綁定 View 和 名稱,第一個頁面 ListActivity 啓動第二個頁面 PageActivity 的時候,要有過渡動畫,對於ListActivity來說,應該是 點擊的View ,而 PageActivity ,應該是 對應位置的View (mCurPosition == position);

而 從 PageActivity 返回的時候, 應該共享 點擊的View,而 ListActivity 應該是 對應位置的 View,所以得動態改變 ListActivity 的共享 View;具體要通過監聽 setExitSharedElementCallback :

public class ListActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        super.onCreate(savedInstanceState);

        // ...省略代碼

        ActivityCompat.setExitSharedElementCallback(this, new SharedElementCallback() {
            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                super.onMapSharedElements(names, sharedElements);
                // 動態改變 ListActivity 的 共享View
                sharedElements.put("share", getItemViewByPosition(PageActivity.mCurPosition));
            }
        });
    }

    public View getItemViewByPosition(int position) {
        for (int i = 0; i < mListView.getChildCount(); i++) {
            View itemView = mListView.getChildAt(i);
            if (position == (int) itemView.getTag(R.id.position)) {
                return itemView;
            }
        }
        return null;
    }

    class MyListAdapter extends BaseAdapter {
        // ...省略代碼

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // ...省略代碼

            img.setTag(R.id.position, position);

            // ...省略代碼
            return convertView;
        }
    }
}

總結:

1,要用過渡動畫,Activity需要 

getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);

2,因爲是Android 5.0之後纔有 Transition,所以建議用 v4兼容包,ActivityOptionsCompat,ActivityCompat;或者自己判斷版本號;

3,使用共享元素的動畫效果非常簡單,只需要分別爲兩個需要共享的元素設置相同的transitionName,並在ActivityOptions.makeSceneTransitionAnimation中將需要共享的元素作爲參數傳遞過去即可;

4,共享元素名稱 TransitionName, Java代碼設置:ViewCompat.setTransitionName(img, "share");

或者 XML裏面設置: android:transitionName="share"

5,合理使用 setExitSharedElementCallback 方法監聽,動態改變共享元素;

 

最後附上 github上 源碼:

https://github.com/miLLlulei/Transitions5.0

歡迎大家 star ~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章