Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - How to create a transition from an item in listview to a whole activity?

What I want is that when the user clicks a list item in a ListView, it converts to a whole activity (as you can see in the following example), but I was not able to find a tutorial explaining this and, actually, I do not know how this movement is called.

In other words, what I want to achieve is:

  1. Increase List Item elevation when it is clicked (as you can see in the right gif)

  2. Expand and transform list item to the next fragment/activity layout that contains detailed information about the clicked item

enter image description here

I have tried a lot of transitions but with no luck. Can anyone help me out to accomplish this?

like image 689
Antonio Avatar asked Oct 28 '15 15:10

Antonio


People also ask

How pass data from ListView to another activity in flutter?

Implement ListView 's OnItemClickListener, once you handle this event, try to get the location of the row that was clicked. Once you get it, access that particular row position in the source array (or whatever else you're having). This way, you'll have the data that you want to pass to another activity.

What is transition animation in android?

Android's transition framework allows you to animate all kinds of motion in your UI by simply providing the starting layout and the ending layout.

When to use RecyclerView?

Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events. If you want to use a RecyclerView , you will need to work with the following: RecyclerView. Adapter - To handle the data collection and bind it to the view.


2 Answers

I build a small sample application that transitions between two activities with the desired effect: Sample Application

However the transitions in the provided gifs are slightly different. The transition in the gif on the left side transitions the list element into the content area of the second activity (Toolbar stays in place). In the gif on the right side the transition transforms the list element into the complete screen of the second activity. The following code provides the effect in the left gif. However it should be possible to adapt the solution with minor modifications to achieve the transition in the right gif.

Note this only works on Lollipop. However it is possible to mock a different effect on older devices. Furthermore the sole purpose of the provided code is to show how it could be done. Don't use this directly in your app.

MainActivity:

public class MainActivity extends AppCompatActivity {      MyAdapter myAdapter;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          setSupportActionBar((Toolbar) findViewById(R.id.toolbar));         ListView listView = (ListView) findViewById(R.id.list_view);          myAdapter = new MyAdapter(this, 0, DataSet.get());          listView.setAdapter(myAdapter);          listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {             @Override             public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {                 startTransition(view, myAdapter.getItem(position));             }         });     }      private void startTransition(View view, Element element) {         Intent i = new Intent(MainActivity.this, DetailActivity.class);         i.putExtra("ITEM_ID", element.getId());          Pair<View, String>[] transitionPairs = new Pair[4];         transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar         transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)          // We also want to transition the status and navigation bar barckground. Otherwise they will flicker         transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);         transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);         Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();          ActivityCompat.startActivity(MainActivity.this, i, b);     } } 

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">      <android.support.v7.widget.Toolbar         android:id="@+id/toolbar"         android:layout_width="match_parent"         android:layout_height="?attr/actionBarSize"         android:background="@color/colorPrimary"         android:transitionName="toolbar" />      <ListView         android:id="@+id/list_view"         android:layout_width="match_parent"         android:layout_height="match_parent" />  </LinearLayout> 

DetailActivity:

public class DetailActivity extends AppCompatActivity {      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_detail);          setSupportActionBar((Toolbar) findViewById(R.id.toolbar));          long elementId = getIntent().getLongExtra("ITEM_ID", -1);         Element element = DataSet.find(elementId);           ((TextView) findViewById(R.id.title)).setText(element.getTitle());         ((TextView) findViewById(R.id.description)).setText(element.getDescription());          // if we transition the status and navigation bar we have to wait till everything is available         TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);         // set a custom shared element enter transition         TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);     } } 

activity_detail.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">      <android.support.v7.widget.Toolbar         android:id="@+id/toolbar"         android:layout_width="match_parent"         android:layout_height="?attr/actionBarSize"         android:background="@color/colorPrimary"         android:transitionName="toolbar" />      <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="#abc"         android:orientation="vertical"         android:paddingBottom="200dp"         android:transitionName="content_area"         android:elevation="10dp">          <TextView             android:id="@+id/title"             android:layout_width="match_parent"             android:layout_height="wrap_content" />          <TextView             android:id="@+id/description"             android:layout_width="match_parent"             android:layout_height="wrap_content" />     </LinearLayout> </LinearLayout> 

detail_activity_shared_element_enter_transition.xml (/res/transition/):

<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"     android:transitionOrdering="together">     <changeBounds/>     <changeTransform/>     <changeClipBounds/>     <changeImageTransform/>     <transition class="my.application.transitions.ElevationTransition"/> </transitionSet> 

my.application.transitions.ElevationTransition:

@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ElevationTransition extends Transition {      private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";      public ElevationTransition() {     }      public ElevationTransition(Context context, AttributeSet attrs) {         super(context, attrs);     }      @Override     public void captureStartValues(TransitionValues transitionValues) {         captureValues(transitionValues);     }      @Override     public void captureEndValues(TransitionValues transitionValues) {         captureValues(transitionValues);     }      private void captureValues(TransitionValues transitionValues) {         Float elevation = transitionValues.view.getElevation();         transitionValues.values.put(PROPNAME_ELEVATION, elevation);     }      @Override     public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {         if (startValues == null || endValues == null) {             return null;         }          Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);         Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);         if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {             return null;         }          final View view = endValues.view;         ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);         a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {             @Override             public void onAnimationUpdate(ValueAnimator animation) {                 view.setElevation((float)animation.getAnimatedValue());             }         });          return a;     } } 

TransitionHelper:

public class TransitionHelper {      public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)             return;          final View decor = activity.getWindow().getDecorView();         if (decor == null)             return;         activity.postponeEnterTransition();         decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {             @TargetApi(Build.VERSION_CODES.LOLLIPOP)             @Override             public boolean onPreDraw() {                 decor.getViewTreeObserver().removeOnPreDrawListener(this);                 activity.startPostponedEnterTransition();                 return true;             }         });     }      public static void setSharedElementEnterTransition(final Activity activity, int transition) {         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)             return;         activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));     } } 

So what are the different parts here: We have two activities. During the transition four views are transitioned between the activities.

  • Toolbar: like in the left gif the toolbar doesn't move with the rest of the content.

  • ListView element View -> becomes the content view of the DetailActivity

  • StatusBar and NavigationBar Background: If we don't add these views to the set of transitioned views they will fade out and back in during the transition. This however requires to delay the enter transition (see: TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar)

In the MainActivity the transitioned views are added to the Bundle that is used to start the DetailActivity. Furthermore the transitioned views need to be named (transitionName) in both activities. This can be done in the layout xml as well as programatically.

The default set of transitions, that is used during the shared element transition, affects different aspects of the view(for example: view bounds - see 2). However differences in the elevation of a view are not animated. This is why the presented solution utilizes the custom ElevationTransition.

like image 93
Andreas Wenger Avatar answered Oct 09 '22 17:10

Andreas Wenger


try this.. Material-Animations

blueIconImageView.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {         Intent i = new Intent(MainActivity.this, SharedElementActivity.class);          View sharedView = blueIconImageView;         String transitionName = getString(R.string.blue_name);          ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);         startActivity(i, transitionActivityOptions.toBundle());     } }); 

SharedElements

like image 44
Carlos.V Avatar answered Oct 09 '22 16:10

Carlos.V