利用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 ~~

猜你喜欢

转载自blog.csdn.net/miLLlulei/article/details/81236194