做一个简单的共享元素Activity跳转

安卓的共享元素动画是个很给力的存在.

但是可能由于只能运行在5.0或以上的系统上,所以感觉普及率一直不高.

ps.现在看到大部分共享元素动画,都是在rom内置app里看到的.很好理解,自己做的rom,当然能确定是5.0以上的.单个app开发就不是这回事了.

 

有些开发者会想做一些通用的库,以此想整合代码,让共享元素动画这方面的代码更加简单.但实际使用效果感觉一般.

所以我也只能总结一下要完成共享元素动画,一般的步骤有哪些.

 

先上图看效果:

 

一.准备待共享的实体

观看上面的gif可以稍微总结得出.这共享元素所共享的东西可以分为两部分.

1.内容实体   2.控件属性

 

对于1.内容实体来说,我这里有一张头像图片,一个黑色字的名称,一个灰色字的描述.

所以我建了个bean来存放

 

public class Person implements Parcelable {

    public String name;
    public String avatar;
    public int defaultAvatarResId;
    public String desc;
//下面略

 

 

对于2.控件属性,这里有控件相对屏幕的位置(x, y), 还有控件的宽高. 还需要有一个资源id. 这样从第一个Activity进入到第二个Activity时候, 可以根据传来的资源id来找到.

同样也建了个bean来存放

 

public class SharedElement implements Parcelable {

    public int resId;
    public int x;
    public int y;
    public int width;
    public int height;

 

 


二.给前后两个Activity写xml, 需要有相同的id

因为需要到要获取各控件的属性, 给控件加以动画. 所以需要有前后两Activity中, 那些有共享元素动画的控件, 需要有相同的id加以识别.

 

 

三.startActivity里, intent放好需要共享的内容

如上面第一点说的两部分.内容实体Person和控件属性.

然后使用overridePendingTransition把默认切换动画去掉.

 

Intent intent = new Intent(MainActivity.this, PersonDetailActivity.class);
intent.putExtra(PersonDetailActivity.EXTRA_PERSON, person);
intent.putParcelableArrayListExtra(PersonDetailActivity.EXTRA_ELEMENTS,
        ViewUtil.getSharedElement(MainActivity.this, holder.mIvAvatar, holder.mTvName, holder.mTvDesc));
startActivity(intent);
overridePendingTransition(0, 0);

写了个Util方法, 传入控件后得到控件属性列表

 

 

public static ArrayList<SharedElement> getSharedElement(Activity aty, View ...views) {
    ArrayList<SharedElement> elements = new ArrayList<>();
    for (View view : views) {
        SharedElement element = new SharedElement();
        element.resId = view.getId();
        element.width = view.getWidth();
        element.height = view.getHeight();
        int []location = new int[2];
        view.getLocationInWindow(location);
        element.x = location[0];
        element.y = location[1];
        elements.add(element);
    }
    return elements;
}

 


四.进入第二个Activity

 

 

 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_person_detail_page);
    ButterKnife.bind(this);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    //intent获取内容, 设置到当前页面
    Person person = getIntent().getParcelableExtra(EXTRA_PERSON);
    if (TextUtils.isEmpty(person.avatar)) {
        Glide.with(PersonDetailActivity.this).load(R.drawable.default_avatar_1).into(mIvAvatar);
    } else {
        Glide.with(PersonDetailActivity.this).load(person.avatar).into(mIvAvatar);
    }
    mTvName.setText(person.name);
    mTvDesc.setText(person.desc);

    //共享元素的动画
    mElements = getIntent().getParcelableArrayListExtra(EXTRA_ELEMENTS);
    animating = true;
    for (int i = 0; i< mElements.size(); i++){
        final int j = i;
        final SharedElement element = mElements.get(i);
        final View view = findViewById(element.resId);

        view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                int []location = new int[2];
                view.getLocationInWindow(location);
                int x = location[0];
                int y = location[1];
                PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", element.x-x, 0);
                PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("translationY", element.y-y, 0);
                PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleX", element.width*1.0f/view.getWidth(), 1f);
                PropertyValuesHolder pvh4 = PropertyValuesHolder.ofFloat("scaleY", element.height*1.0f/view.getHeight(), 1f);
                view.setPivotX(0);
                view.setPivotY(0);
                ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3, pvh4).setDuration(duration).start();
            }
        });
    }

    //其他动画
    mFlBackground.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mFlBackground.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            TypedValue tv = new TypedValue();
            getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
            int actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
            ObjectAnimator.ofFloat(mFlBackground, "translationY", -mFlBackground.getHeight()+actionBarHeight, 0).setDuration(duration).start();
        }
    });
    mNsvContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mNsvContent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            int []location = new int[2];
            mNsvContent.getLocationInWindow(location);
            int y = location[1];
            ObjectAnimator animator = ObjectAnimator.ofFloat(mNsvContent, "translationY", ScreenUtil.getScreenHeight(PersonDetailActivity.this)-y, 0).setDuration(duration);
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    animating = false;
                }
            });
            animator.start();
        }
    });
}

分为了几部分.

 

1.首先把person实体从Intent拿出来, 设置到对应控件.

2.把控件的各属性从Intent拿出来, 在一个for循环里, 通过resId找到对应控件, 根据(x, y)设置平移动画, 根据宽高设置缩放动画. 这里通过PropertyValuesHolder来设置, 它可以用来设置多个一起运行的属性动画.

3.设置一些非共享元素的动画. 从gif图可以看到, 为了整个视觉效果的协调, 我把标题栏和滚动的内容栏也设置了一个平移的动画. 这样新页面全部内容都是有动画演变来的.很和谐哈哈

 


五.退出第二个Activity的动画

 

@Override
public void onBackPressed() {
    if (animating == true) {
        return;
    }
    //共享元素动画
    animating = true;
    for (int i=0; i<mElements.size(); i++){
        final int j = i;
        final SharedElement element = mElements.get(i);
        final View view = findViewById(element.resId);

        int []location = new int[2];
        view.getLocationInWindow(location);
        int x = location[0];
        int y = location[1];
        PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 0, element.x-x);
        PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("translationY", 0, element.y-y);
        PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleX", 1f, element.width*1.0f/view.getWidth());
        PropertyValuesHolder pvh4 = PropertyValuesHolder.ofFloat("scaleY", 1f, element.height*1.0f/view.getHeight());
        ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3, pvh4).setDuration(duration).start();
    }

    //其他动画
    TypedValue tv = new TypedValue();
    getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
    int actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
    ObjectAnimator.ofFloat(mFlBackground, "translationY", 0, -mFlBackground.getHeight()+actionBarHeight).setDuration(duration).start();

    int []location = new int[2];
    mNsvContent.getLocationInWindow(location);
    int y = location[1];
    ObjectAnimator animator = ObjectAnimator.ofFloat(mNsvContent, "translationY", 0, ScreenUtil.getScreenHeight(PersonDetailActivity.this)-y).setDuration(duration);
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            PersonDetailActivity.super.onBackPressed();
            overridePendingTransition(0, 0);
        }
    });
    animator.start();
}

也分为两部分, 共享元素动画和其他动画

 

 

 

 

 

 

放上github地址

https://github.com/yaodiwei/SharedElementTransition

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值