VerticalGridFragment.java revision dfb60d0af5d49da05c584d74245c616263f26b65
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.app;
15
16import android.support.v17.leanback.R;
17import android.support.v17.leanback.widget.Row;
18import android.support.v17.leanback.widget.VerticalGridPresenter;
19import android.support.v17.leanback.widget.ObjectAdapter;
20import android.support.v17.leanback.widget.OnItemClickedListener;
21import android.support.v17.leanback.widget.OnItemSelectedListener;
22import android.support.v17.leanback.widget.SearchOrbView;
23import android.app.Fragment;
24import android.graphics.drawable.Drawable;
25import android.os.Bundle;
26import android.util.Log;
27import android.view.LayoutInflater;
28import android.view.View;
29import android.view.ViewGroup;
30import android.widget.ImageView;
31import android.widget.TextView;
32
33/**
34 * Leanback fragment for a vertical grid.
35 *
36 * Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
37 * an {@link ObjectAdapter}.
38 */
39public class VerticalGridFragment extends Fragment {
40    private static final String TAG = "VerticalGridFragment";
41    private static boolean DEBUG = false;
42
43    // TODO: remove Params
44    private Params mParams;
45
46    private String mTitle;
47    private Drawable mBadgeDrawable;
48    private ObjectAdapter mAdapter;
49    private VerticalGridPresenter mGridPresenter;
50    private VerticalGridPresenter.ViewHolder mGridViewHolder;
51    private OnItemSelectedListener mOnItemSelectedListener;
52    private OnItemClickedListener mOnItemClickedListener;
53    private View.OnClickListener mExternalOnSearchClickedListener;
54    private int mSelectedPosition = -1;
55
56    private ImageView mBadgeView;
57    private TextView mTitleView;
58    private ViewGroup mBrowseTitle;
59    private SearchOrbView mSearchOrbView;
60    private boolean mShowingTitle = true;
61
62    // transition related
63    private static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
64    private Object mTitleTransition;
65    private Object mSceneWithTitle;
66    private Object mSceneWithoutTitle;
67
68    @Deprecated
69    public static class Params {
70        private String mTitle;
71        private Drawable mBadgeDrawable;
72
73        /**
74         * Sets the badge image.
75         */
76        public void setBadgeImage(Drawable drawable) {
77            mBadgeDrawable = drawable;
78        }
79
80        /**
81         * Returns the badge image.
82         */
83        public Drawable getBadgeImage() {
84            return mBadgeDrawable;
85        }
86
87        /**
88         * Sets a title for the browse fragment.
89         */
90        public void setTitle(String title) {
91            mTitle = title;
92        }
93
94        /**
95         * Returns the title for the browse fragment.
96         */
97        public String getTitle() {
98            return mTitle;
99        }
100    }
101
102    /**
103     * Set fragment parameters.
104     * @deprecated Use methods on the fragment directly.
105     */
106    @Deprecated
107    public void setParams(Params params) {
108        mParams = params;
109        setBadgeDrawable(mParams.mBadgeDrawable);
110        setTitle(mParams.mTitle);
111    }
112
113    /**
114     * Returns fragment parameters.
115     * @deprecated Use methods on the fragment directly.
116     */
117    @Deprecated
118    public Params getParams() {
119        return mParams;
120    }
121
122    /**
123     * Sets the badge drawable displayed in the title area.
124     */
125    public void setBadgeDrawable(Drawable drawable) {
126        if (drawable != mBadgeDrawable) {
127            mBadgeDrawable = drawable;
128            setBadgeViewImage();
129        }
130    }
131
132    /**
133     * Returns the badge drawable.
134     */
135    public Drawable getBadgeDrawable() {
136        return mBadgeDrawable;
137    }
138
139    /**
140     * Sets a title for the fragment.
141     */
142    public void setTitle(String title) {
143        mTitle = title;
144        if (mTitleView != null) {
145            mTitleView.setText(mTitle);
146        }
147    }
148
149    /**
150     * Returns the title for the fragment.
151     */
152    public String getTitle() {
153        return mTitle;
154    }
155
156    /**
157     * Sets the grid presenter.
158     */
159    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
160        if (gridPresenter == null) {
161            throw new IllegalArgumentException("Grid presenter may not be null");
162        }
163        mGridPresenter = gridPresenter;
164        mGridPresenter.setOnItemSelectedListener(mRowSelectedListener);
165        if (mOnItemClickedListener != null) {
166            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
167        }
168    }
169
170    /**
171     * Returns the grid presenter.
172     */
173    public VerticalGridPresenter getGridPresenter() {
174        return mGridPresenter;
175    }
176
177    /**
178     * Sets the object adapter for the fragment.
179     */
180    public void setAdapter(ObjectAdapter adapter) {
181        mAdapter = adapter;
182        updateAdapter();
183    }
184
185    /**
186     * Returns the object adapter.
187     */
188    public ObjectAdapter getAdapter() {
189        return mAdapter;
190    }
191
192    final private OnItemSelectedListener mRowSelectedListener = new OnItemSelectedListener() {
193        @Override
194        public void onItemSelected(Object item, Row row) {
195            int position = mGridViewHolder.getGridView().getSelectedPosition();
196            if (DEBUG) Log.v(TAG, "row selected position " + position);
197            onRowSelected(position);
198            if (mOnItemSelectedListener != null) {
199                mOnItemSelectedListener.onItemSelected(item, row);
200            }
201        }
202    };
203
204    /**
205     * Sets an item selection listener.
206     */
207    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
208        mOnItemSelectedListener = listener;
209    }
210
211    private void onRowSelected(int position) {
212        if (position != mSelectedPosition) {
213            if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(position)) {
214                // if has no sibling in front of it,  show title
215                if (!mShowingTitle) {
216                    sTransitionHelper.runTransition(mSceneWithTitle, mTitleTransition);
217                    mShowingTitle = true;
218                }
219            } else if (mShowingTitle) {
220                sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleTransition);
221                mShowingTitle = false;
222            }
223            mSelectedPosition = position;
224        }
225    }
226
227    /**
228     * Sets an item clicked listener.
229     */
230    public void setOnItemClickedListener(OnItemClickedListener listener) {
231        mOnItemClickedListener = listener;
232        if (mGridPresenter != null) {
233            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
234        }
235    }
236
237    /**
238     * Returns the item clicked listener.
239     */
240    public OnItemClickedListener getOnItemClickedListener() {
241        return mOnItemClickedListener;
242    }
243
244    /**
245     * Sets a click listener for the search affordance.
246     *
247     * The presence of a listener will change the visibility of the search affordance in the
248     * title area. When set to non-null the title area will contain a call to search action.
249     *
250     * The listener onClick method will be invoked when the user click on the search action.
251     *
252     * @param listener The listener.
253     */
254    public void setOnSearchClickedListener(View.OnClickListener listener) {
255        mExternalOnSearchClickedListener = listener;
256        if (mSearchOrbView != null) {
257            mSearchOrbView.setOnOrbClickedListener(listener);
258        }
259    }
260
261    private void setBadgeViewImage() {
262        if (mBadgeView == null) {
263            return;
264        }
265        mBadgeView.setImageDrawable(mBadgeDrawable);
266        if (mBadgeDrawable != null) {
267            mBadgeView.setVisibility(View.VISIBLE);
268            mTitleView.setVisibility(View.GONE);
269        } else {
270            mBadgeView.setVisibility(View.GONE);
271            mTitleView.setVisibility(View.VISIBLE);
272        }
273    }
274
275    @Override
276    public View onCreateView(LayoutInflater inflater, ViewGroup container,
277            Bundle savedInstanceState) {
278        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
279                container, false);
280
281        mBrowseTitle = (ViewGroup) root.findViewById(R.id.browse_title_group);
282        mBadgeView = (ImageView) mBrowseTitle.findViewById(R.id.browse_badge);
283        mTitleView = (TextView) mBrowseTitle.findViewById(R.id.browse_title);
284        mSearchOrbView = (SearchOrbView) mBrowseTitle.findViewById(R.id.browse_orb);
285        if (mExternalOnSearchClickedListener != null) {
286            mSearchOrbView.setOnOrbClickedListener(mExternalOnSearchClickedListener);
287        }
288
289        setBadgeViewImage();
290        mTitleView.setText(mTitle);
291
292        mSceneWithTitle = sTransitionHelper.createScene(root, new Runnable() {
293            @Override
294            public void run() {
295                mBrowseTitle.setVisibility(View.VISIBLE);
296            }
297        });
298        mSceneWithoutTitle = sTransitionHelper.createScene(root, new Runnable() {
299            @Override
300            public void run() {
301                mBrowseTitle.setVisibility(View.GONE);
302            }
303        });
304        mTitleTransition = sTransitionHelper.createTransitionSet(false);
305        Object fade = sTransitionHelper.createFadeTransition(
306                TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
307        Object changeBounds = sTransitionHelper.createChangeBounds(false);
308        sTransitionHelper.addTransition(mTitleTransition, fade);
309        sTransitionHelper.addTransition(mTitleTransition, changeBounds);
310        sTransitionHelper.excludeChildren(mTitleTransition, R.id.browse_grid_dock, true);
311        return root;
312    }
313
314    @Override
315    public void onViewCreated(View view, Bundle savedInstanceState) {
316        ViewGroup gridDock = (ViewGroup) view.findViewById(R.id.browse_grid_dock);
317        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
318        gridDock.addView(mGridViewHolder.view);
319
320        updateAdapter();
321    }
322
323    @Override
324    public void onStart() {
325        super.onStart();
326        mGridViewHolder.getGridView().requestFocus();
327    }
328
329    @Override
330    public void onDestroyView() {
331        super.onDestroyView();
332        mGridViewHolder = null;
333    }
334
335    /**
336     * Sets the selected item position.
337     */
338    public void setSelectedPosition(int position) {
339        mSelectedPosition = position;
340        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
341            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
342        }
343    }
344
345    private void updateAdapter() {
346        if (mGridViewHolder != null) {
347            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
348            if (mSelectedPosition != -1) {
349                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
350            }
351        }
352    }
353}
354