VerticalGridPresenter.java revision 739e3805bf2785e6773aede5e2e1643f537305f9
1739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout/*
2739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Copyright (C) 2014 The Android Open Source Project
3739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
4739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * in compliance with the License. You may obtain a copy of the License at
6739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
7739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
8739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
9739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
10739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
12739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * the License.
13739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout */
14739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutpackage android.support.v17.leanback.widget;
15739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
16739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.R;
17739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.LayoutInflater;
18739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.View;
19739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.ViewGroup;
20739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.util.Log;
21739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
22739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout/**
23739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * A presenter that renders objects in a vertical grid.
24739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
25739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout */
26739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutpublic class VerticalGridPresenter extends Presenter {
27739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static final String TAG = "GridPresenter";
28739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static final boolean DEBUG = false;
29739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
30739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public static class ViewHolder extends Presenter.ViewHolder {
31739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter();
32739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        final VerticalGridView mGridView;
33739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        boolean mInitialized;
34739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
35739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        public ViewHolder(VerticalGridView view) {
36739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            super(view);
37739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridView = view;
38739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
39739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
40739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        public VerticalGridView getGridView() {
41739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            return mGridView;
42739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
43739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
44739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
45739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private int mNumColumns = -1;
46739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private int mZoomFactor;
47739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private OnItemSelectedListener mOnItemSelectedListener;
48739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private OnItemClickedListener mOnItemClickedListener;
49739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
50739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public VerticalGridPresenter() {
51739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        this(FocusHighlight.ZOOM_FACTOR_MEDIUM);
52739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
53739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
54739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public VerticalGridPresenter(int zoomFactor) {
55739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mZoomFactor = zoomFactor;
56739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
57739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
58739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
59739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the number of columns in the vertical grid.
60739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
61739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setNumberOfColumns(int numColumns) {
62739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (numColumns < 0) {
63739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            throw new IllegalArgumentException("Invalid number of columns");
64739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
65739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mNumColumns != numColumns) {
66739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mNumColumns = numColumns;
67739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
68739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
69739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
70739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
71739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the number of columns in the vertical grid.
72739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
73739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public int getNumberOfColumns() {
74739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mNumColumns;
75739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
76739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
77739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
78739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public final ViewHolder onCreateViewHolder(ViewGroup parent) {
79739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        ViewHolder vh = createGridViewHolder(parent);
80739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.mInitialized = false;
81739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        initializeGridViewHolder(vh);
82739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (!vh.mInitialized) {
83739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            throw new RuntimeException("super.initializeGridViewHolder() must be called");
84739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
85739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return vh;
86739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
87739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
88739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
89739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Subclass may override this to inflate a different layout.
90739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
91739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    protected ViewHolder createGridViewHolder(ViewGroup parent) {
92739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        View root = LayoutInflater.from(parent.getContext()).inflate(
93739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                R.layout.lb_browse_grid, parent, false);
94739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return new ViewHolder((VerticalGridView) root.findViewById(R.id.browse_grid));
95739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
96739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
97739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    protected void initializeGridViewHolder(ViewHolder vh) {
98739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mNumColumns == -1) {
99739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            throw new IllegalStateException("Number of columns must be set");
100739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
101739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (DEBUG) Log.v(TAG, "mNumColumns " + mNumColumns);
102739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.getGridView().setNumColumns(mNumColumns);
103739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.mInitialized = true;
104739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
105739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        FocusHighlightHelper.setupBrowseItemFocusHighlight(vh.mItemBridgeAdapter, mZoomFactor);
106739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
107739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        final ViewHolder gridViewHolder = vh;
108739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.getGridView().setOnChildSelectedListener(new OnChildSelectedListener() {
109739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            @Override
110739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
111739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                selectChildView(gridViewHolder, view);
112739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            }
113739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        });
114739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
115739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.mItemBridgeAdapter.setAdapterListener(new ItemBridgeAdapter.AdapterListener() {
116739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            @Override
117739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            public void onCreate(final ItemBridgeAdapter.ViewHolder itemViewHolder) {
118739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                // Only when having an OnItemClickListner, we attach the OnClickListener.
119739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                if (getOnItemClickedListener() != null) {
120739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                    final View itemView = itemViewHolder.getViewHolder().view;
121739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                    itemView.setOnClickListener(new View.OnClickListener() {
122739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                        @Override
123739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                        public void onClick(View view) {
124739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                            if (getOnItemClickedListener() != null) {
125739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                                // Row is always null
126739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                                getOnItemClickedListener().onItemClicked(itemViewHolder.mItem, null);
127739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                            }
128739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                        }
129739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                    });
130739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                }
131739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            }
132739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        });
133739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
134739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
135739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
136739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
137739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (DEBUG) Log.v(TAG, "onBindViewHolder " + item);
138739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        ViewHolder vh = (ViewHolder) viewHolder;
139739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.mItemBridgeAdapter.setAdapter((ObjectAdapter) item);
140739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.getGridView().setAdapter(vh.mItemBridgeAdapter);
141739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
142739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
143739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
144739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
145739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (DEBUG) Log.v(TAG, "onUnbindViewHolder");
146739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        ViewHolder vh = (ViewHolder) viewHolder;
147739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.mItemBridgeAdapter.setAdapter(null);
148739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        vh.getGridView().setAdapter(null);
149739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
150739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
151739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
152739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the item selected listener.
153739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Since this is a grid the row parameter is always null.
154739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
155739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public final void setOnItemSelectedListener(OnItemSelectedListener listener) {
156739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mOnItemSelectedListener = listener;
157739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
158739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
159739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
160739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the item selected listener.
161739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
162739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public final OnItemSelectedListener getOnItemSelectedListener() {
163739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mOnItemSelectedListener;
164739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
165739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
166739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
167739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the item clicked listener.
168739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * OnItemClickedListener will override {@link View.OnClickListener} that
169739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
170739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * So in general, developer should choose one of the listeners but not both.
171739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
172739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public final void setOnItemClickedListener(OnItemClickedListener listener) {
173739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mOnItemClickedListener = listener;
174739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
175739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
176739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
177739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the item clicked listener.
178739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
179739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public final OnItemClickedListener getOnItemClickedListener() {
180739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mOnItemClickedListener;
181739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
182739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
183739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private void selectChildView(ViewHolder vh, View view) {
184739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (getOnItemSelectedListener() != null) {
185739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            ItemBridgeAdapter.ViewHolder ibh = (view == null) ? null :
186739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                (ItemBridgeAdapter.ViewHolder) vh.getGridView().getChildViewHolder(view);
187739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
188739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            getOnItemSelectedListener().onItemSelected(ibh == null ? null : ibh.mItem, null);
189739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
190739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    };
191739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout}
192