AndroidStudio 2.3 Beta 1
I am trying to get transitions work with fragments, how the image I am using doesn't transition. It just pop up as normal.
I have created a simple App to try and get this to work. I have 2 fragments ListMovieFragment
and DetailMovieFragment
. And 1 MainActivity
.
The user will click the image in ListMovieFragment
to transition to DetailMovieFragment
.
This is my Transition xml change_image_transform:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
</transitionSet>
ListMovieFragment:
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;
}
}
MainActivity
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();
}
}
}
The layout for 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>
Layout for 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>
The string name for the transition name:
<string name="transition_poster_image">imagePoster</string>
The implementation seems simple so I think my mistake is something i'm overlooking.
Many thanks for any suggestions,
You have two problems in your code, inside your onMovieSelected
method:
ListMovieFragment
and then apply transition logic to it.
But you forgot that you already have the instance of this fragment (you were created it in onCreate
method).
So you need to retrieve the existing ListMovieFragment
object from FragmentManager
, and apply your transitions to it.DetailMovieFragment
, but then suddenly replacing the ListMoveFragment
with the new one. So your fixed onMovieSelected
method will be:
@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();
}
}
Now this should work.
P.S. I've used your code and run it, and noticed you have some strange transitions, so if you will have some issues, check this great article, how to make smooth and user-friendly transitions with fragments:)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With