【问题标题】:sharedElment transition using fragments not transitioningsharedElment 使用片段不转换的转换
【发布时间】:2016-12-22 17:59:42
【问题描述】:
AndroidStudio 2.3 Beta 1

我正在尝试让过渡与片段一起工作,我正在使用的图像如何不过渡。它只是正常弹出。

我创建了一个简单的应用程序来尝试让它工作。我有 2 个片段 ListMovieFragmentDetailMovieFragment。还有 1 个MainActivity

用户将单击ListMovieFragment 中的图像转换为DetailMovieFragment

这是我的转换 xml change_image_transform:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeImageTransform/>
</transitionSet>

列表电影片段:

public class ListMovieFragment extends Fragment {
    public interface MovieSelectedListener {
        void onMovieSelected(int movieId);
    }
    private MovieSelectedListener mMovieSelectedListener;

    public ListMovieFragment() {
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mMovieSelectedListener = (MovieSelectedListener)context;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mMovieSelectedListener = null;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        final View view = inflater.inflate(R.layout.fragment_list, container, false);
        final ImageView ivMoviePoster = (ImageView)view.findViewById(R.id.ivMoviePoster);

        ivMoviePoster.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mMovieSelectedListener != null) {
                    mMovieSelectedListener.onMovieSelected(12345);
                }
            }
        });

        Glide.with(getActivity())
                .load("https://image.tmdb.org/t/p/w185/qjiskwlV1qQzRCjpV0cL9pEMF9a.jpg")
                .placeholder(R.drawable.placeholder_poster)
                .centerCrop()
                .crossFade()
                .into(ivMoviePoster);

        return view;
    }
}

DetailMovieFragment

public class DetailMovieFragment extends Fragment {
    public DetailMovieFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_detail, container, false);

        final ImageView ivMovieDetailPoster = (ImageView)view.findViewById(R.id.ivMovieDetailPoster);

        Glide.with(getActivity())
                .load("https://image.tmdb.org/t/p/w185/qjiskwlV1qQzRCjpV0cL9pEMF9a.jpg")
                .placeholder(R.drawable.placeholder_poster)
                .centerCrop()
                .crossFade()
                .into(ivMovieDetailPoster);

        return view;
    }
}

主活动

public class MainActivity extends AppCompatActivity implements ListMovieFragment.MovieSelectedListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(savedInstanceState == null) {
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.activity_main, new ListMovieFragment(), "listmoviefragment");
            fragmentTransaction.commit();
        }
    }

    @Override
    public void onMovieSelected(int movieId) {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            /* Get the fragments that will be using the transition */
            ListMovieFragment listMovieFragment = new ListMovieFragment();
            DetailMovieFragment detailMovieFragment = new DetailMovieFragment();

            /* Inflate the transition */
            Transition changeTransition = TransitionInflater
                    .from(MainActivity.this)
                    .inflateTransition(R.transition.change_image_transform);

            Transition explodeTransition = TransitionInflater
                    .from(MainActivity.this)
                    .inflateTransition(android.R.transition.explode);

            /* Set the exit and return on the source fragment (ListMovieFragment) */
            listMovieFragment.setSharedElementReturnTransition(changeTransition);
            listMovieFragment.setExitTransition(explodeTransition);

            /* Set the enter on the destination fragment (MovieDetailFragment) */
            detailMovieFragment.setSharedElementEnterTransition(changeTransition);
            detailMovieFragment.setEnterTransition(explodeTransition);

            /* Get the shared imageview from the source fragment (MovieListFragment) */
            final ImageView ivSharedImage = (ImageView)findViewById(R.id.ivMoviePoster);

            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.activity_main, new DetailMovieFragment(), "detailmoviefragment");
            fragmentTransaction.addToBackStack("detailmoviefragment");
            fragmentTransaction.addSharedElement(ivSharedImage, getResources().getString(R.string.transition_poster_image));
            fragmentTransaction.commit();
        }
        else {
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.activity_main, new DetailMovieFragment(), "detailmoviefragment");
            fragmentTransaction.addToBackStack("detailmoviefragment");
            fragmentTransaction.commit();
        }
    }

    @Override
    public void onBackPressed() {
        if(getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStackImmediate();
        }
        else {
            super.onBackPressed();
        }
    }
}

ListMovieFragment 的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="6dp">

    <ImageView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ivMoviePoster"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:src="@drawable/placeholder_poster"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"
        android:transitionName="@string/transition_poster_image">
    </ImageView>
</LinearLayout>

DetailMovieFragment 的布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="me.androidbox.fragmenttransitions.detail.DetailMovieFragment">
    <ImageView
        android:id="@+id/ivMovieDetailPoster"
        android:layout_width="140dp"
        android:layout_height="160dp"
        android:layout_marginEnd="16dp"
        android:layout_marginTop="112dp"
        android:adjustViewBounds="true"
        android:scaleType="fitXY"
        android:layout_gravity="end"
        android:transitionName="@string/transition_poster_image"/>
</FrameLayout>

转换名称的字符串名称:

<string name="transition_poster_image">imagePoster</string>

实现看起来很简单,所以我认为我的错误是我忽略的。

非常感谢您的任何建议,

【问题讨论】:

    标签: android android-fragments android-transitions shared-element-transition


    【解决方案1】:

    您的代码中有两个问题,在您的 onMovieSelected 方法中:

    1. 您正在创建ListMovieFragment新实例,然后对其应用转换逻辑。 但是您忘记了您已经拥有此片段的实例(您是在onCreate 方法中创建的)。 因此,您需要从 FragmentManager 中检索现有的 ListMovieFragment 对象,并将您的转换应用到它。
    2. 您正在将转换逻辑应用于DetailMovieFragment 的一个实例,但随后突然将ListMoveFragment 替换为新实例。

    所以您的固定onMovieSelected 方法将是:

    @Override
    public void onMovieSelected(int movieId) {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            /* Get the fragments that will be using the transition */
            ListMovieFragment listMovieFragment = (ListMovieFragment) getSupportFragmentManager().findFragmentByTag("listmoviefragment");
            DetailMovieFragment detailMovieFragment = new DetailMovieFragment();
    
            /* Inflate the transition */
            Transition changeTransition = TransitionInflater
                    .from(MainActivity.this)
                    .inflateTransition(R.transition.change_image_transform);
    
            Transition explodeTransition = TransitionInflater
                    .from(MainActivity.this)
                    .inflateTransition(android.R.transition.explode);
    
            /* Set the exit and return on the source fragment (ListMovieFragment) */
            listMovieFragment.setSharedElementReturnTransition(changeTransition);
            listMovieFragment.setExitTransition(explodeTransition);
    
            /* Set the enter on the destination fragment (MovieDetailFragment) */
            detailMovieFragment.setSharedElementEnterTransition(changeTransition);
            detailMovieFragment.setEnterTransition(explodeTransition);
    
            /* Get the shared imageview from the source fragment (MovieListFragment) */
            final ImageView ivSharedImage = (ImageView)findViewById(R.id.ivMoviePoster);
    
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.activity_main, detailMovieFragment, "detailmoviefragment");
            fragmentTransaction.addToBackStack("detailmoviefragment");
            fragmentTransaction.addSharedElement(ivSharedImage, getResources().getString(R.string.transition_poster_image));
            fragmentTransaction.commit();
        } else {
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.activity_main, new DetailMovieFragment(), "detailmoviefragment");
            fragmentTransaction.addToBackStack("detailmoviefragment");
            fragmentTransaction.commit();
        }
    }
    

    现在应该可以了。

    PS 我已经使用了你的代码并运行了它,发现你有一些奇怪的过渡,所以如果你有一些问题,检查这个great article,如何使平滑和用户-带有片段的友好过渡:)

    【讨论】:

    • 感谢您的帮助。
    • 进行所有更正后。进入 detailFragment 的过渡看起来很棒。但是当按下后退按钮时,过渡不会过渡。我认为当从后台堆栈中弹出片段时,这会自动发生。这是正确的吗?
    • 是的,您可能需要将返回转换添加到detailMovieFragment,如下所示:detailMovieFragment.setSharedElementReturnTransition(changeTransition);。猜猜它应该可以解决您的问题。
    • 这实际上不起作用。不过,感谢您的帮助。
    • 嗯,一件事 - 如果您从 MainActivity 中删除您的 onBackPressed 方法实现会怎样?但离开返回过渡。
    【解决方案2】:

    在添加到片段事务时不要创建新的对象片段,重用您应用了进入和退出转换的现有片段。

          public class MainActivity extends AppCompatActivity implements ListMovieFragment.MovieSelectedListener {
    
                @Override
                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_main);
                    if(savedInstanceState == null) {
                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            ListMovieFragment listMovieFragment = new ListMovieFragment();
                            Transition changeTransition = TransitionInflater
                                    .from(MainActivity.this)
                                    .inflateTransition(R.transition.change_image_transform);
    
                            Transition explodeTransition = TransitionInflater
                                    .from(MainActivity.this)
                                    .inflateTransition(android.R.transition.explode);
                            listMovieFragment.setSharedElementReturnTransition(changeTransition);
                            listMovieFragment.setExitTransition(explodeTransition);
                            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                            //don't create new  ListMovieFragment use existing listMovieFragment instance
                            fragmentTransaction.add(R.id.activity_main, listMovieFragment, "listmoviefragment");
                            fragmentTransaction.commit();
                        }else {
                            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                            fragmentTransaction.add(R.id.activity_main, new ListMovieFragment(), "listmoviefragment");
                            fragmentTransaction.commit();
                        }
                    }
                }
    
                @Override
                public void onMovieSelected(int movieId) {
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        /* Get the fragments that will be using the transition */
                        ListMovieFragment listMovieFragment = new ListMovieFragment();
                        DetailMovieFragment detailMovieFragment = new DetailMovieFragment();
    
                        /* Inflate the transition */
                        Transition changeTransition = TransitionInflater
                                .from(MainActivity.this)
                                .inflateTransition(R.transition.change_image_transform);
    
                        Transition explodeTransition = TransitionInflater
                                .from(MainActivity.this)
                                .inflateTransition(android.R.transition.explode);
    
                        /* Set the exit and return on the source fragment (ListMovieFragment) */
                        listMovieFragment.setSharedElementReturnTransition(changeTransition);
                        listMovieFragment.setExitTransition(explodeTransition);
    
                        /* Set the enter on the destination fragment (MovieDetailFragment) */
                        detailMovieFragment.setSharedElementEnterTransition(changeTransition);
                        detailMovieFragment.setEnterTransition(explodeTransition);
    
                        /* Get the shared imageview from the source fragment (MovieListFragment) */
                        final ImageView ivSharedImage = (ImageView)findViewById(R.id.ivMoviePoster);
    
                        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                        //don't create new  DetailMovieFragment use existing detailMovieFragment instance
                        fragmentTransaction.replace(R.id.activity_main, detailMovieFragment, "detailmoviefragment");
                        fragmentTransaction.addToBackStack("detailmoviefragment");
                        fragmentTransaction.addSharedElement(ivSharedImage, getResources().getString(R.string.transition_poster_image));
                        fragmentTransaction.commit();
                    }
                    else {
                        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                        fragmentTransaction.replace(R.id.activity_main, new DetailMovieFragment(), "detailmoviefragment");
                        fragmentTransaction.addToBackStack("detailmoviefragment");
                        fragmentTransaction.commit();
                    }
                }
                @Override
                public void onBackPressed() {
                    if(getSupportFragmentManager().getBackStackEntryCount() > 0) {
                        getSupportFragmentManager().popBackStackImmediate();
                    }
                    else {
                        super.onBackPressed();
                    }
                }
            }
    

    【讨论】:

    • 感谢帮助
    猜你喜欢
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多