android共享元素动画失效,Android 共享元素的基本使用以及一些需要注意的坑

先说fragment 到fragment如何实现共享元素。

假设我们recycleview(fragment中)的某一个item中点击图片,去到另外一个item中(可以理解为微信朋友圈查看照片)。

首先我们要在adapter中的每一个图片imageview(或者是其他的)设置transitionName,防止重复

关键代码

@Override

public void onBindViewHolder(final MyViewHolder holder, final int position) {

//省略

ViewCompat.setTransitionName(holder.getImageView(), url);

//省略

}

使用ViewCompat.setTransitionName为每一个image绑定他自己的照片url,防止重复(前提是你的照片url不重复)

我们将adapter的图片的fragment定义为界面1 显示大图的fragment定义为界面2

此时我们的界面1的每一个imageView 都绑定了transitionName,然后我们需要界面2的照片也设置一个transiotionName

这是界面2的xml设置

android:id="@+id/detail_image"

android:layout_width="240dp"

android:layout_height="240dp"

android:transitionName="TransitionName"

tools:ignore="UnusedAttribute"/>

trasitionName可以静态xml设置 也可以动态设置

两边都设置后 就可以进行跳转了

//界面2的fragment

DetailFragment detailFragment = DetailFragment.newInstance(position);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

detailFragment.setSharedElementEnterTransition(new DetailTransition());

setExitTransition(new Fade());

detailFragment.setEnterTransition(new Fade());

detailFragment.setSharedElementReturnTransition(new DetailTransition());

}

getActivity().getSupportFragmentManager().beginTransaction()

.addSharedElement(holder.getImageView(), "TransitionName")

.replace(R.id.main_cl_container, detailFragment)

.addToBackStack(null)

.commit();

其中需要注意的是 addSharedElement这里 第一个参数是界面一的imageview 参数2是界面2的imageview的transitionName。

05e3b99ce5ce

image

以上就是fragment跳转fragment的关键代码。

那么有哪些坑呢?

不能用add只能用replace

fragment跳转的时候 不能用add 只能用replace。我在这里卡住一段时间 最后发现不能用add

加载网络图片会有问题

因为如果下载图片时间比transition共享的动画慢的话 动画会有问题

怎么解决呢

There's no direct equivalent in Fragment Transitions because Fragments use FragmentTransaction and we can't really postpone something that is supposed to happen in a transaction.

To get the equivalent, you can add a Fragment and hide it in a transaction, then when the Fragment is ready, remove the old Fragment and show the new Fragment in a transaction.

getFragmentManager().beginTransaction()

.add(R.id.container, fragment2)

.hide(fragment2)

.commit();

Later, when fragment2 is ready:

getFragmentManager().beginTransaction()

.addSharedElement(sharedElement, "name")

.remove(fragment1)

.show(fragment2)

.commit();

使用activity 而不使用fragment。

我强烈建议使用方法二(因为方法1没成功,只能用2)

使用activty的话 要提到两个关键字

postponeEnterTransition()和startPostponedEnterTransition()

第一个是暂停共享元素动画,第二个是开始共享元素动画。这两个方法只能在activity中使用,因此建议使用activity

好,上代码

首先照旧,在界面1的adapter中 绑定每一个imageview的transitionName

ViewCompat.setTransitionName(holder.getImageView(), url);

界面1可以是activity也可以是fragment 都不影响

然后跳转方式要换成activity的跳转方式

ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(

getActivity(),

new Pair(view,

o.getText())

);

Intent intent = new Intent(getActivity(), PhotoActivity.class);

intent.putExtra("url", o.getText());

ActivityCompat.startActivity(getActivity(), intent, activityOptions.toBundle());

其中new Pair(view,o.getText()) 第一个参数就是要进行共享元素的view(在这里是imageView) 第二个参数就是界面2的view的transitionName。界面1和界面2的view的transitionName要一致,因此我传递了url过去界面2

界面2:

在界面2的activty中 直接套上之前的fragment就行

然后设置界面2的imageview的transitionName,这里我们动态进行设置

getActivity().postponeEnterTransition();//先停止

ViewCompat.setTransitionName(photoView, url);//然后设置transitionName, photoview为界面2要进行共享元素的view

然后使用glide4.0加载网络图片(如果是glide之前版本 写法不一样 不可照搬)

Glide

.with(App.getContext())

.load(url)

.apply(options)

.listener(new RequestListener() {

@Override

public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {

scheduleStartPostponedTransition(photoView);

return true;

}

@Override

public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {

photoView.setImageDrawable(resource);

scheduleStartPostponedTransition(photoView);

return true;

}

})

.into(photoView);

重点是listener里面的scheduleStartPostponedTransition()方法

if (sharedElement == null) return;

sharedElement.getViewTreeObserver().addOnPreDrawListener(

new ViewTreeObserver.OnPreDrawListener() {

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

@Override

public boolean onPreDraw() {

if (sharedElement == null) return false;

sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);

getActivity().startPostponedEnterTransition();//开启动画

return true;

}

});

通过activity 就能使用这两个方法进行延时了。

还需要注意的是

如果发现动画能运行 但是定位到图片上的时候有偏差 那可能是你设置了centerCrop之类的属性 查看一下 去掉 就行了

fragment多次调用onCreateView导致动画部分失效

如果还是不行得话 看看有没有可能是fragment多次调用onCreateView,打一下log

解决方法就是判断是否是第一次加载root view

private View rootView;

//oncreateview

if (null != rootView) {

//不是第一次

ViewGroup parent = (ViewGroup) rootView.getParent();

if (parent != null) {

parent.removeView(rootView);

}

unbinder = ButterKnife.bind(this, rootView);这一句是因为用了ButterKnife注入 没有用得忽视就行

} else {

//第一次

rootView = inflater.inflate(R.layout.fragment_gallery, container, false);

unbinder = ButterKnife.bind(this, rootView);//这一句是因为用了ButterKnife注入 没有用得忽视就行

EventBus.getDefault().register(this);

initRv();

initToolbar();

initData();

initEvent();

}

return rootView;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值