反向共享元素转换

时间:2015-02-01 13:59:39

标签: android transition shared-element-transition

我目前正在使用以下代码将屏幕右侧的块转换为左侧的共享元素:

 FragmentDetail newFragment = FragmentDetail.newInstance(id);

 setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.trans_move));
 setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
 View block = view.findViewById(R.id.blocks);
 block.setTransitionName("block");

 newFragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.trans_move));
 newFragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));


 newFragment.setTransitionId(block.getTransitionName());
 FragmentTransaction trans = getFragmentManager().beginTransaction();
 trans.replace(R.id.container, newFragment);
 trans.addToBackStack(null);
 trans.addSharedElement(block, block.getTransitionName());
 trans.commit();

这正是我想要的方式,但是我希望在按下后退按钮时反转效果,将项目重新设置为动画。原样,爆炸动画播放,但过渡不会。

非常感谢任何帮助。

由于 约什

6 个答案:

答案 0 :(得分:6)

具有Android导航组件的KOTLIN

对于使用Android导航组件时在这里寻找此问题答案的任何人,您都可以通过将以下行添加到起始片段的onViewCreated函数中来使反向过渡动画起作用:

        postponeEnterTransition()
        view.doOnPreDraw { startPostponedEnterTransition() }

如果要通过单击RecyclerView项打开第二个片段,通常会使用它。

答案 1 :(得分:2)

假设您有两个片段ABA提交片段事务以启动片段B

然后,这意味着应在A上设置退出和重新转换,并且应在B上设置输入和返回转换。

看起来你在调用片段上调用setSharedElementReturnTransition而不是在这种情况下调用片段(newFragment),这可能会导致问题。

顺便说一句,您应该考虑在片段的set*****Transition()方法中调用setSharedElement*****Transition()onCreate()方法,而不是在提交片段事务之前立即调用。{1}}和onCreate()方法。如果片段被破坏并重新创建,那么这些过渡将被遗忘......因此在{{1}}中设置它们会更加安全。

答案 2 :(得分:2)

切换
trans.replace(R.id.container, newFragment);

trans.hide(oldFragment).add(R.id.container, newFragment).show(newFragment)

它应该工作(如我的情况)。 恢复共享片段转换似乎只有在隐藏旧的转换时才有效,而不是替换它。

答案 3 :(得分:1)

重新定义布局后,使用block.setTransitionName("block");设置的

块转换名称将丢失,因为您的块将被新视图替换,而该视图尚未设置其transitionName。要避免这种情况,请修改您调用Fragment的onCreateView方法,以便在布局已经膨胀时不要对其进行充气。

例如:

private View inflatedLayout = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (inflatedLayout == null) {
        inflatedLayout = inflater.inflate(R.layout.fragment_caller, container, false);
    }
    return inflatedLayout;
}

答案 4 :(得分:0)



我遇到了同样的问题。我买了解决方案。 你知道,这个问题有很多原因。我只是表明我的方式。 希望能帮到你。

有两个片段。 一个人有一个RecyclerView小部件:

<强> ListFragment.java

public class ListFragment extends Fragment implements RecyclerItemInter {

@Bind(R.id.recycler_view)
RecyclerView recyclerView;

private OnListItemClickListener onListItemClickListener;

public void setOnListItemClickListener(ListFragment.OnListItemClickListener onListItemClickListener) {
    this.onListItemClickListener = onListItemClickListener;
}

public ListFragment() {
}

public static ListFragment newInstance() {
    ListFragment fragment = new ListFragment();
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_list, container, false);
    ButterKnife.bind(this, view);
    recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
    RecyclerAdapter2 adapter = new RecyclerAdapter2(BEAUTY_BEANS);
    recyclerView.setAdapter(adapter);
    adapter.setItemInter(this);
    return view;
}

private static final BeautyBean[] BEAUTY_BEANS = {
        new BeautyBean("Avril Lavigne1", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
        new BeautyBean("Avril Lavigne2", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
        new BeautyBean("Avril Lavigne3", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
        new BeautyBean("Avril Lavigne4", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
        new BeautyBean("Avril Lavigne5", "Avril was born in Canada, the Canadian singer, songwriter creators, actors.")
};


@Override
public void onDestroyView() {
    super.onDestroyView();
    ButterKnife.unbind(this);
}

@Override
public void onItemClick(View view, int position) {
}

@Override
public void onIvClick(RecyclerAdapter2.ViewHolder holder, int position) {
    OtherFragment otherFragment = OtherFragment.newInstance();
    otherFragment.setSharedElementEnterTransition(new CustomTransition());
    otherFragment.setSharedElementReturnTransition(new CustomTransition());

    /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        otherFragment.setEnterTransition(new Fade());
        setExitTransition(new Fade());
    }*/

    getActivity().getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.frame_layout, otherFragment)
            .addToBackStack(null)
            .addSharedElement(holder.getPicIv(), getString(R.string.transition_img))
            .commit();
}

然后你应该将TransitionName设置为RecyclerView中的每个ImageView:

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    if (items[position].getImageId() != 0) {
        holder.getPicIv().setImageResource(items[position].getImageId());
    }
    ViewCompat.setTransitionName(holder.getPicIv(), String.valueOf(position) + "_beauty");

    holder.getTitleTv().setText(items[position].getName());
    holder.getDescTv().setText(items[position].getDesc());
    holder.getLinearLayout().setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (null != itemInter) {
                itemInter.onItemClick(holder.itemView, position);
            }
        }
    });
    holder.getPicIv().setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (null != itemInter) {
                itemInter.onIvClick(holder, position);
            }
        }
    });
}

单击列表跳转到OtherFragment。

<强> OtherFragment.java

public class OtherFragment extends Fragment {

public OtherFragment() {
}

public static OtherFragment newInstance() {
    OtherFragment fragment = new OtherFragment();
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_other, container, false);
}

}

<强> fragment_other.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jacksen.supportlibrarydemo.fragment.OtherFragment">


<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/bg_detail_header"
    android:transitionName="@string/transition_img" />


<android.support.design.widget.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="end|bottom"
    android:layout_margin="@dimen/fab_margin"
    android:src="@drawable/ic_backup_white_36dp"
    android:transitionName="@string/transition_fab"
    app:borderWidth="0dp"
    app:elevation="5dp"
    app:pressedTranslationZ="10dp"
    app:rippleColor="@color/color_gray" />

问题的症结在于这个xml。 在开头,我设置属性“transitionName”和它的父布局。 实际上我们不需要在父布局上添加属性。

只需将 transitionName 添加到您想要转化的内容中。

好的,这是我的解决方案。

答案 5 :(得分:0)

Joe Muller的答案是正确的,我是用Java编写的

@Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    postponeEnterTransition();
    view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            startPostponedEnterTransition();
            view.getViewTreeObserver().removeOnPreDrawListener(this);
            return false;
        }
    });
}

如果开始转换位于适配器内部,则可以解决此问题