blob: 525ed4035e67b7ce76a6cd0aac590cde1732e927 [file] [log] [blame]
Alexander Lucas97842ff2014-03-07 14:56:55 -08001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.adaptertransition;
18
19import android.os.Bundle;
20import android.support.v4.app.ActivityCompat;
21import android.support.v4.app.Fragment;
22import android.transition.AutoTransition;
23import android.transition.Scene;
24import android.transition.Transition;
25import android.transition.TransitionManager;
26import android.view.LayoutInflater;
27import android.view.Menu;
28import android.view.MenuInflater;
29import android.view.MenuItem;
30import android.view.View;
31import android.view.ViewGroup;
32import android.widget.AbsListView;
33import android.widget.FrameLayout;
34import android.widget.GridView;
35import android.widget.ListView;
36
37/**
38 * Main screen for AdapterTransition sample.
39 */
40public class AdapterTransitionFragment extends Fragment implements Transition.TransitionListener {
41
42 /**
43 * Since the transition framework requires all relevant views in a view hierarchy to be marked
44 * with IDs, we use this ID to mark the root view.
45 */
46 private static final int ROOT_ID = 1;
47
48 /**
49 * This is where we place our AdapterView (ListView / GridView).
50 */
51 private FrameLayout mContent;
52
53 /**
54 * This is where we carry out the transition.
55 */
56 private FrameLayout mCover;
57
58 /**
59 * This list shows our contents. It can be ListView or GridView, and we toggle between them
60 * using the transition framework.
61 */
62 private AbsListView mAbsListView;
63
64 /**
65 * This is our contents.
66 */
67 private MeatAdapter mAdapter;
68
69 public static AdapterTransitionFragment newInstance() {
70 return new AdapterTransitionFragment();
71 }
72
73 public AdapterTransitionFragment() {
74 }
75
76 @Override
77 public void onCreate(Bundle savedInstanceState) {
78 super.onCreate(savedInstanceState);
79 setHasOptionsMenu(true);
80 }
81
82 @Override
83 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
84 // We use a ListView at first
85 mAbsListView = (AbsListView) inflater.inflate(R.layout.fragment_meat_list, container, false);
86 mAdapter = new MeatAdapter(inflater, R.layout.item_meat_list);
87 return inflater.inflate(R.layout.fragment_adapter_transition, container, false);
88 }
89
90 @Override
91 public void onViewCreated(View view, Bundle savedInstanceState) {
92 // Retaining references for FrameLayouts that we use later.
93 mContent = (FrameLayout) view.findViewById(R.id.content);
94 mCover = (FrameLayout) view.findViewById(R.id.cover);
95 // We are attaching the list to the screen here.
96 mAbsListView.setAdapter(mAdapter);
97 mContent.addView(mAbsListView);
98 }
99
100 @Override
101 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
102 inflater.inflate(R.menu.fragment_adapter_transition, menu);
103 }
104
105 @Override
106 public void onPrepareOptionsMenu(Menu menu) {
107 // We change the look of the icon every time the user toggles between list and grid.
108 MenuItem item = menu.findItem(R.id.action_toggle);
109 if (null != item) {
110 if (mAbsListView instanceof ListView) {
111 item.setIcon(R.drawable.ic_action_grid);
112 } else {
113 item.setIcon(R.drawable.ic_action_list);
114 }
115 }
116 }
117
118 @Override
119 public boolean onOptionsItemSelected(MenuItem item) {
120 switch (item.getItemId()) {
121 case R.id.action_toggle: {
122 toggle();
123 return true;
124 }
125 }
126 return false;
127 }
128
129 @Override
130 public void onTransitionStart(Transition transition) {
131 }
132
133 // BEGIN_INCLUDE(on_transition_end)
134 @Override
135 public void onTransitionEnd(Transition transition) {
136 // When the transition ends, we remove all the views from the overlay and hide it.
137 mCover.removeAllViews();
138 mCover.setVisibility(View.INVISIBLE);
139 }
140 // END_INCLUDE(on_transition_end)
141
142 @Override
143 public void onTransitionCancel(Transition transition) {
144 }
145
146 @Override
147 public void onTransitionPause(Transition transition) {
148 }
149
150 @Override
151 public void onTransitionResume(Transition transition) {
152 }
153
154 /**
155 * Toggle the UI between ListView and GridView.
156 */
157 private void toggle() {
158 // We use mCover as the overlay on which we carry out the transition.
159 mCover.setVisibility(View.VISIBLE);
160 // This FrameLayout holds all the visible views in the current list or grid. We use this as
161 // the starting Scene of the Transition later.
162 FrameLayout before = copyVisibleViews();
163 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
164 FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
165 mCover.addView(before, params);
166 // Swap the actual list.
167 swapAbsListView();
168 // We also swap the icon for the toggle button.
169 ActivityCompat.invalidateOptionsMenu(getActivity());
170 // It is now ready to start the transition.
171 mAbsListView.post(new Runnable() {
172 @Override
173 public void run() {
174 // BEGIN_INCLUDE(transition_with_listener)
175 Scene scene = new Scene(mCover, copyVisibleViews());
176 Transition transition = new AutoTransition();
177 transition.addListener(AdapterTransitionFragment.this);
178 TransitionManager.go(scene, transition);
179 // END_INCLUDE(transition_with_listener)
180 }
181 });
182 }
183
184 /**
185 * Swap ListView with GridView, or GridView with ListView.
186 */
187 private void swapAbsListView() {
188 // We save the current scrolling position before removing the current list.
189 int first = mAbsListView.getFirstVisiblePosition();
190 // If the current list is a GridView, we replace it with a ListView. If it is a ListView,
191 // a GridView.
192 LayoutInflater inflater = LayoutInflater.from(getActivity());
193 if (mAbsListView instanceof GridView) {
194 mAbsListView = (AbsListView) inflater.inflate(
195 R.layout.fragment_meat_list, (ViewGroup) mAbsListView.getParent(), false);
196 mAdapter = new MeatAdapter(inflater, R.layout.item_meat_list);
197 } else {
198 mAbsListView = (AbsListView) inflater.inflate(
199 R.layout.fragment_meat_grid, (ViewGroup) mAbsListView.getParent(), false);
200 mAdapter = new MeatAdapter(inflater, R.layout.item_meat_grid);
201 }
202 mAbsListView.setAdapter(mAdapter);
203 // We restore the scrolling position here.
204 mAbsListView.setSelection(first);
205 // The new list is ready, and we replace the existing one with it.
206 mContent.removeAllViews();
207 mContent.addView(mAbsListView);
208 }
209
210 /**
211 * Copy all the visible views in the mAbsListView into a new FrameLayout and return it.
212 *
213 * @return a FrameLayout with all the visible views inside.
214 */
215 private FrameLayout copyVisibleViews() {
216 // This is the FrameLayout we return afterwards.
217 FrameLayout layout = new FrameLayout(getActivity());
218 // The transition framework requires to set ID for all views to be animated.
219 layout.setId(ROOT_ID);
220 // We only copy visible views.
221 int first = mAbsListView.getFirstVisiblePosition();
222 int index = 0;
223 while (true) {
224 // This is one of the views that we copy. Note that the argument for getChildAt is a
225 // zero-oriented index, and it doesn't usually match with its position in the list.
226 View source = mAbsListView.getChildAt(index);
227 if (null == source) {
228 break;
229 }
230 // This is the copy of the original view.
231 View destination = mAdapter.getView(first + index, null, layout);
232 assert destination != null;
233 destination.setId(ROOT_ID + first + index);
234 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
235 source.getWidth(), source.getHeight());
236 params.leftMargin = (int) source.getX();
237 params.topMargin = (int) source.getY();
238 layout.addView(destination, params);
239 ++index;
240 }
241 return layout;
242 }
243
244}